Главная страница
Навигация по странице:

  • Условные операторы

  • Регулярные выражения

  • Выполение запросов выполение запросов


    Скачать 495.28 Kb.
    НазваниеВыполение запросов выполение запросов
    Дата08.11.2022
    Размер495.28 Kb.
    Формат файлаpptx
    Имя файлаLektsia_4.pptx
    ТипЛекции
    #777888

    ВЫПОЛЕНИЕ ЗАПРОСОВ

    ВЫПОЛЕНИЕ ЗАПРОСОВ


    Метод find используется в MongoDB для выполнения запросов. При выполнении запроса возвращается подмножество документов в коллекции, при этом документов может не быть вообще либо это может быть вся коллекция. Какие документы возвращаются, определяется первым аргументом метода, который представляет собой документ, определяющий критерии запроса.
    Пустой документ запроса (т. е. {}) соответствует всему, что есть в коллекции. Если методу find не предоставлен документ запроса, по умолчанию используется {}.
    Например, строка соответствует каждому документу в коллекции с (и возвращает эти документы в пакетном режиме).
    > db.c.find()

    ВЫПОЛЕНИЕ ЗАПРОСОВ


    Запросить простой тип так же просто, как указать значение, которое вы ищете. Например, чтобы найти все документы, где значение age = 27, можно добавить эту пару типа «ключ/значение» в документ запроса:
    > db.users.find({"age" : 27})
    Если у нас есть строка, которую мы хотим сопоставить, например, ключ «usemame» и значение «joe», мы используем эту пару:
    > db.users.find({"username" : "joe"})
    Можно объединить несколько условий, добавив больше пар типа «ключ/значение» в документ запроса, который интерпретируется как «условие 1 И условие2 И... И условием». Например, чтобы получить всех пользователей, которым 27 лет, с именем «joe», можно выполнить следующий запрос:
    > db.users.find({"username" : "joe", "age" : 27})


    Иногда вам не нужны все пары типа «ключ/значение» в возвращаемом документе. В этом случае можно передать второй аргумент методу find (или findOne), указывая нужные вам ключи. Это уменьшает как объем передаваемых данных, так и время, и память, используемые для декодирования документов на стороне клиента.
    Например, если у вас есть коллекция пользователей и вас интересуют только ключи "username" и "email", можно вернуть лишь эти ключи с помощью следующего запроса:
    > db.users.find({}, {"username" : 1, "email" : 1})
    {
    "_id" : ObjectId("4ba0f0dfd22aa494fd523620"),
    "username" : "joe",
    "email" : "joe@example.com"
    }
    Как видно из предыдущего вывода, ключ "_id" возвращается по умолчанию, даже если он не запрашивается специально.


    Вы также можете использовать этот второй параметр, чтобы исключить определенные пары типа «ключ/значение» из результатов запроса.
    Например, у вас могут быть документы с различными ключами, и единственное, что вы знаете, – это то, что вы ни за что не хотите возвращать ключ "fatal_weakness":
    > db.users.find({}, {"fatal_weakness" : 0})
    Приведенный ниже код также может предотвратить возвращение "_id":
    > db.users.find({}, {"username" : 1, "_id" : 0})
    {
    "username" : "joe",
    }

    ОГРАНИЧЕНИЯ


    Есть некоторые ограничения на запросы. Значение документа запроса должно быть константой для базы данных. (Это может быть обычная переменная в вашем собственном коде.) То есть она не может ссылаться на значение другого ключа в документе. Например, если бы мы вели учет и у нас были бы ключи "in_stock" и "num_sold", мы не могли бы сравнивать их значения с помощью следующего запроса:
    > db.stock.find({"in_stock" : "this.num_sold"}) //Это не сработает;
    Есть способы сделать это, но, как правило, вы будете получать лучшую производительность, слегка реструктурировав документ, поэтому «обычного» запроса будет достаточно. В этом примере мы могли бы использовать ключи "initial_stock" и "in_stock". Затем каждый раз, когда кто-то покупает товар, мы уменьшаем значение ключа "in_stock" на единицу. Наконец, мы можем сделать простой запрос, чтобы проверить, каких товаров нет в наличии:
    > db.stock.find({"in_stock" : 0})

    КРИТЕРИИ ЗАПРОСА. УСЛОВНЫЕ ОПЕРАТОРЫ


    Запросы могут выходить за рамки точного соответствия, описанного в предыдущем разделе; они могут соответствовать более сложным критериям, таким как диапазоны, операторы OR и отрицание.
    Условные операторы
    "$lt", "$lte", "$gt", "$gte","$eq" – все это операторы сравнения, соответствующие <, <=, > и >= и = соответственно. Их можно комбинировать для поиска диапазона значений.
    Например, чтобы найти пользователей в возрасте от 18 до 30 лет, можно выполнить следующий запрос:
    > db.users.find({"age": {"$gte": 18, "$lte": 30}})
    При этом будут найдены все документы, где поле "age" было больше или равно 18 и меньше или равно 30. Эти типы запросов диапазона часто полезны, когда речь идет о датах.
    Например, чтобы найти людей, которые зарегистрировались до 1 января 2007 года, можно выполнить следующий запрос:
    > start = new Date("01/01/2007")
    > db.users.find({"registered" : {"$lt" : start}})
    Чтобы запросить документы, в которых значение ключа не равно определенному значению, нужно использовать другой условный оператор "$ne", который означает «не равно». Если вы хотите найти всех пользователей, у которых нет имени «joe», можно запросить их таким образом:
    > db.users.find({"username" : {"$ne" : "joe"}})


    В MongoDB есть два способа выполнить запрос оператором OR. Оператор "$in" может использоваться для запроса различных значений для одного ключа. Оператор "$or" является более общим; его можно использовать для запроса любого из заданных значений по нескольким ключам.
    Если у вас имеется более одного возможного значения для одного ключа, используйте массив критериев с "$in". Например, предположим, что мы проводим розыгрыш и номера выигрышных билетов – 75, 542 и 390. Чтобы найти все три этих документа, можно создать следующий запрос:
    > db.raffle.find({"ticket_no": {"$in": [725, 542, 390]}})
    Оператор "$in" очень гибкий и позволяет указывать критерии различных типов, а также значения. Например, если мы постепенно переносим нашу схему, чтобы использовать имена пользователей вместо идентификаторов пользователей, можно запросить любой из них:
    > db.users.find({"user_id": {"$in": [12345, "joe"]}})


    Противоположностью оператору "$in" является оператор "$nin", который возвращает документы, которые не соответствуют ни одному из критериев в массиве. Если мы хотим вернуть всех тех, кто ничего не выиграл во время лотереи, это можно сделать с помощью следующего запроса:
    > db.raffle.find({"ticket_no": {"$ nin": [725, 542, 390]}})
    Этот запрос возвращает всех, у кого не было билетов с этими номерами.
    Оператор "$in" дает вам запрос OR для одного ключа, но что, если нам нужно найти документы, где "ticket_no" равен 725 или значение "winner" равно true? Для этого типа запроса нам понадобится использовать условный оператор "$or".
    "$or" принимает массив возможных критериев. В случае с лотереей использование оператора "$or" будет выглядеть так:
    > db.raffle.find({"$or": [{"ticket_no": 725}, {"winner": true}]})
    "$or" может содержать другие условия. Если, например, мы хотим сопоставить любое из трех значений "ticket_no" или ключ "winner", можно использовать это:
    > db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}}, {"winner" : true}]})

    КРИТЕРИИ ЗАПРОСА. КРИТЕРИЙ $NOT


    "$not" является метаусловным оператором: его можно применять поверх любых других критериев. В качестве примера давайте рассмотрим оператор модуля "$mod".
    "$mod" запрашивает ключи, значения которых при делении на первое заданное значение имеют остаток от второго значения:
    > db.users.find({"id_num": {"$mod": [5, 1]}})
    Предыдущий запрос возвращает пользователей с номерами 1, 6, 11, 16
    и т. д. Если вместо этого мы хотим вернуть пользователей с номерами 2, 3, 4, 5, 7, 8, 9, 10, 12 и т. д., можно использовать оператор "$not":
    > db.users.find({"id_num": {"$not": {"$mod": [5, 1]}}})
    "$not" может быть особенно полезен в сочетании с регулярными выражениями для поиска всех документов, которые не соответствуют заданному шаблону.

    ЗАПРОСЫ ДЛЯ ОПРЕДЕЛЕННЫХ ТИПОВ


    null
    Тип null ведет себя немного странно. Он соответствует самому себе, поэтому если у нас есть коллекция со следующими документами:
    > db.c.find()
    { "_id" : ObjectId("4ba0f0dfd22aa494fd523621"), "y" : null }
    { "_id" : ObjectId("4ba0f0dfd22aa494fd523622"), "y" : 1 }
    мы можем запросить документы, у которых ключ "y" равен нулю, ожидаемым образом:
    > db.c.find({"y" : null})
    { "_id" : ObjectId("4ba0f0dfd22aa494fd523621"), "y" : null }
    Однако null также соответствует значению «не существует». Таким образом, запрос ключа со значением null вернет все документы, в которых этот ключ отсутствует
    > db.c.find({"z": null})
    Если мы хотим найти только ключи со значением null, можно проверить, что ключ имеет значение null и что он существует, используя условный оператор "$exists":
    > db.c.find({"z" : {"$eq" : null, "$exists" : true}})

    ЗАПРОСЫ ДЛЯ ОПРЕДЕЛЕННЫХ ТИПОВ


    Регулярные выражения
    Оператор "$regex" предоставляет возможности регулярных выражений для сопоставления с образцом в запросах. Регулярные выражения полезны для гибкого сопоставления строк. Например, если нам нужно найти всех пользователей с именем «Joe» или «joe», можно использовать регулярное выражение для нечувствительного к регистру сопоставления:
    > db.users.find( {"name" : {"$regex" : /joe/i}})

    ЗАПРОСЫ ЭЛЕМЕНТОВ МАССИВА


    Запросы элементов массива разработаны таким образом, чтобы вести себя так же, как запросы скаляров. Например, если массив представляет собой список фруктов:
    > db.food.insertOne({"fruit": ["apple", "banana", "peach"]})
    приведенный ниже запрос будет успешно совпадать с документом:
    > db.food.find({"fruit" : "banana"})
    Мы можем запросить его практически так же, как если бы у нас был документ, который выглядел бы как (недопустимый) документ {"fruit" : "apple", "fruit": "banana", "fruit": "peach"}.

    ЗАПРОСЫ ЭЛЕМЕНТОВ МАССИВА


    Если вам нужно сопоставить массивы по нескольким элементам, можно использовать оператор "$all". Он позволяет сопоставить список элементов. Например, предположим, что мы создаем коллекцию из трех элементов:
    > db.food.insertOne({"_ id" : 1, "fruit": ["apple", "banana", "peach"]})
    > db.food.insertOne({"_ id" : 2, "fruit": ["apple", "kumquat", "orange"]})
    > db.food.insertOne({"_ id" : 3, "fruit": ["cherry", "banana", "apple"]})
    Затем мы можем найти все документы с элементами "apple" и "banana", выполнив запрос с помощью оператора "$all":
    > db.food.find({fruit : {$ all : ["apple", "banana"]}})
    {"_id" : 1, "fruit" : ["apple", "banana", "peach"]}
    {"_id" : 3, "fruit" : ["cherry", "banana", "apple"]}

    ЗАПРОСЫ ЭЛЕМЕНТОВ МАССИВА


    "$size"
    Полезным условным оператором для запроса массивов является оператор "$size", который позволяет запрашивать массивы заданного размера.
    Пример:
    > db.food.find({"fruit" : {"$ size": 3}})
    Один из распространенных запросов – получение диапазона размеров. Оператор "$size" нельзя объединить с другим условным оператором (в данном примере с "$gt"), но этот запрос можно выполнить, добавив в документ ключ "size". Затем каждый раз, когда вы добавляете элемент в массив, увеличивайте значение "size". Если исходное обновление выглядело так:
    > db.food.update(criteria, {"$push" : {"fruit" : "strawberry"}})
    можно просто поменять его на это:
    > db.food.update(criteria, {"$push" : {"fruit" : "strawberry"}, "$inc" : {"size" : 1}})
    Прирост идет очень быстро, поэтому любое снижение производительности незначительно. Хранение документов, подобных этому, позволяет вам выполнять такие запросы:
    > db.food.find({"size": {"$ gt": 3}})
    К сожалению, данный метод не работает с оператором "$addToSet".

    ЗАПРОСЫ ЭЛЕМЕНТОВ МАССИВА


    "$slice"
    Как упоминалось ранее, второй необязательный аргумент для метода find определяет ключи, которые должны быть возвращены.
    Можно использовать специальный оператор "$slice", чтобы вернуть подмножество элементов для ключа массива.
    Например, предположим, что у нас был документ поста в блоге, и нам нужно вернуть первые 10 комментариев:
    > db.blog.posts.findOne(criteria, {"comments" : {"$slice" : 10}})
    Также, если бы нам были нужны последние 10 комментариев, мы могли бы использовать −10:
    > db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -10}})
    Оператор "$slice" еще может возвращать страницы посреди результатов, принимая смещение и число возвращаемых элементов:
    > db.blog.posts.findOne(criteria, {"comments" : {"$slice" : [23, 10]}})
    Первые 23 элемента будут пропущены, и вернутся элементы с 24-го по 33-й. Если бы в массиве было меньше 33 элементов, он вернул бы как можно больше элементов.
    Если не указано иное, при использовании оператора "$slice" возвращаются все ключи в документе. Это отличается от других спецификаторов ключей, которые подавляют возврат неупомянутых ключей.

    ВОЗВРАТ СОВПАДАЮЩЕГО ЭЛЕМЕНТА МАССИВА


    Совпадающий элемент можно вернуть с помощью оператора $. Учитывая предыдущий пример с блогом, можно получить комментарий Боба с помощью этого запроса:
    > db.blog.posts.find({"comments.name" : "bob"}, {"comments.$" : 1})
    {
    "_id" : ObjectId("4b2d75476cc613d5ee930164"),
    "comments" :
    [
    {
    "name" : "bob",
    "email" : "bob@example.com",
    "content" : "good post."
    }
    ]
    }


    Скаляры (элементы, не являющиеся элементами массива) в документах должны совпадать с каждым предложением критериев запроса.
    Например, если вы запросили {"x": {"$gt": 10, "$lt": 20}}, "x" должно быть больше 10 и меньше 20. Однако если поле документа "x" является массивом, документ совпадает, если существует элемент "x", который совпадает с каждой частью критерия, но каждое предложение запроса может совпадать с другим элементом массива.
    Лучший способ понять это поведение – посмотреть пример. Предположим, у нас есть следующие документы:
    {"x" : 5}
    {"x" : 15}
    {"x" : 25}
    {"x" : [5, 25]}


    Во-первых, можно использовать оператор "$elemMatch", чтобы заставить MongoDB сравнивать оба предложения с одним элементом массива. Однако подвох заключается в том, что этот оператор не будет соответствовать элементам без массивов:
    > db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}}})
    > // Никаких результатов;
    Документ {"x" : 15} больше не совпадает с запросом, поскольку поле "x" не является массивом. Тем не менее у вас должна быть веская причина для смешивания массивов и скалярных значений в поле. Во многих случаях использования смешивания не требуется. Для них оператор "$elemMatch" предлагает хорошее решение для запросов по диапазону к элементам массива.


    Если у вас есть индекс по полю, по которому вы выполняете запрос, можно использовать min и max, чтобы ограничить диапазон индекса, пройденного запросом, значениями "$gt" и "$lt":
    > db.test.find({"x" : {"$gt": 10, "$lt" : 20}}).min ({"x" : 10}).max ({"x" : 20} )
    {"x" : 15}
    Теперь мы проходим индекс только с 10 до 20, пропуская записи 5 и 25.
    min и max можно использовать только тогда, когда у вас есть индекс по полю, по которому вы выполняете запрос, и вы должны передать min и max все поля индекса.
    Использование min и max при запросе по диапазону для документов, которые могут включать в себя массивы, – как правило, неплохая идея. Индексные границы для запроса "$gt"/"$lt" по массиву неэффективны. В основном он принимает любое значение, поэтому будет искать все записи индекса, а не только те, которые находятся в диапазоне.



    написать администратору сайта