Выборка и фильтрация

Последнее обновление: 29.07.2022

Наиболее простой способом выборки документов из коллекции представляет использование функции find(). Действие этой функции во многом аналогично обычному запросу SELECT * FROM Table, который применяется в SQL и который извлекает все строки. Например, чтобы извлечь все документы из коллекции users, созданной в прошлой теме, мы можем использовать команду:

db.users.find()
Извлечение данных из MongoDB

Фильтрация данных

Однако что, если нам надо получить не все документы, а только те, которые удовлетворяют определенному требованию. Например, мы ранее в базу добавили следующие документы:

db.users.insertOne({"name": "Tom", "age": 28, languages: ["english", "spanish"]})
db.users.insertOne({"name": "Bill", "age": 32, languages: ["english", "french"]})
db.users.insertOne({"name": "Tom", "age": 32, languages: ["english", "german"]})

Выведем все документы, в которых name=Tom:

db.users.find({name: "Tom"})

Такой запрос выведет нам два документа, в которых name=Tom.

test> db.users.find({name: "Tom"})
[
  {
    _id: ObjectId("62e2d6a5e75ce6a476c170b3"),
    name: 'Tom',
    age: 28,
    languages: [ 'english', 'spanish' ]
  },
  { _id: ObjectId("62e2d348e75ce6a476c170ae"),
    _id: ObjectId("62e2d6a5e75ce6a476c170b5"),
    name: 'Tom',
    age: 32,s: [ 'english', 'spanish' ]
    languages: [ 'english', 'german' ]
  }
]   _id: ObjectId("62e2d3d5e75ce6a476c170af"),
test>

Теперь более сложный запрос: нам надо вывести те объекты, у которых name=Tom и одновременно age=32. То есть на языке SQL это могло бы выглядеть так: SELECT * FROM Table WHERE Name='Tom' AND Age=32. Данному критерию у нас соответствует последний добавленный объект. Тогда мы можем написать следующий запрос:

db.users.find({name: "Tom", age: 32})

Фильтрация по отсутствующим свойствам

Какие-то документы могут иметь определенное свойство, другие могут его не иметь. Что если мы хотим получить документы, в которых отсутствует определенное свойство? В этом случае для свойства передается значение null. Например, найдем все документы, где отсутствует свойство languages:

db.users.find({languages: null})

Или найдем все документы, где name="Tom", но свойство languages не определено.

db.users.find({name: "Tom", languages: null})

Фильтрация по элементам массива

Также несложно отыскать по элементу в массиве. Например, следующий запрос выводит все документы, у которых в массиве languages есть english:

db.users.find({languages: "english"})

Усложним запрос и получим те документы, у которых в массиве languages одновременно два языка: "english" и "german":

db.users.find({languages: ["english", "german"]})

Причем именно в этом порядке, где "english" определен первым, а "german" - вторым.

Теперь выведем все документы, в которых "english" в массиве languages находится на первом месте:

db.users.find({"languages.0": "english"})

Обратите внимание, что "languages.0" предоставляет сложное свойство и поэтому берется в кавычки. Соответственно если нам надо вывести документы, где english на втором месте (например, ["german", "english"]), то вместо нуля ставим единицу: "languages.1".

Рассмотрим более сложный пример, где элемент массива представляет сложный объект. Допустим, у нас в базе данных следующие документы:

db.users.insertOne({"name": "Bob", "age": 28, friends: [{"name": "Tim"}, {"name": "Tom"}]})
db.users.insertOne({"name": "Tim", "age": 29, friends: [{"name": "Bob"}, {"name": "Tom"}]})
db.users.insertOne({"name": "Sam", "age": 31, friends: [{"name": "Tom"}]})
db.users.insertOne({"name": "Tom", "age": 32, friends: [{"name": "Bob"}, {"name": "Tim"}, {"name": "Sam"}]})

Выберем все документы, где в массиве friends свойство name первого элемента равно "Bob":

test> db.users.find({"friends.0.name": "Bob"})

Консольный вывод:

test> db.users.find({"friends.0.name": "Bob"})
[
  {
    _id: ObjectId("62e39da1c881653067e87901"),
    name: 'Tim',
    age: 29,
    friends: [ { name: 'Bob' }, { name: 'Tom' } ]
  },
  {
    _id: ObjectId("62e39da1c881653067e87903"),
    name: 'Tom',
    age: 32,
    friends: [ { name: 'Bob' }, { name: 'Tim' }, { name: 'Sam' } ]
  }
]
test>

Проекция

Документ может иметь множество полей, но не все эти поля нам могут быть нужны и важны при запросе. И в этом случае мы можем включить в выборку только нужные поля, использовав проекцию. Например, выведем только порцию информации, например, значения полей "age" у все документов, в которых name=Tom:

db.users.find({name: "Tom"}, {age: 1})

Использование единицы в качестве параметра {age: 1} указывает, что запрос должен вернуть только содержание свойства age.

test> db.users.find({name: "Tom"}, {age: 1})
[
  { _id: ObjectId("62e2d6a5e75ce6a476c170b3"), age: 28 },
  { _id: ObjectId("62e2d6a5e75ce6a476c170b5"), age: 32 },
  { _id: ObjectId("62e2d799e75ce6a476c170b7"), age: 28 },
  { _id: ObjectId("62e39da1c881653067e87903"), age: 32 }
]
test>

И обратная ситуация: мы хотим найти все поля документа кроме свойства age. В этом случае в качестве параметра указываем 0:

db.persons.find({name: "Tom"}, {age: 0})

При этом надо учитывать, что даже если мы отметим, что мы хотим получить только поле name, поле _id также будет включено в результирующую выборку. Поэтому, если мы не хотим видеть данное поле в выборке, то надо явным образом указать: {"_id":0}

Альтернативно вместо 1 и 0 можно использовать true и false:

db.users.find({name: "Tom"}, {age: true, _id: false})

Если мы не хотим при этом конкретизировать выборку, а хотим вывести все документы, то можно оставить первые фигурные скобки пустыми:

db.users.find({}, {age: 1, _id: 0})

Запрос к вложенным объектам

Предыдущие запросы применялись к простым объектам. Но документы могут быть очень сложными по структуре. Например, добавим в коллекцию users следующий документ:

db.users.insertOne({"name": "Alex", "age": 28, company: {"name":"Microsoft", "country":"USA"}})

Здесь определяется вложенный объект с ключом company. И чтобы найти все документы, у которых в ключе company вложенное свойство name=microsoft, нам надо использовать оператор точку:

db.users.find({"company.name": "Microsoft"})

Использование JavaScript

Кроме выполнения запросов к базе данных мы можем выполнять выражения JavaScript. Например, мы можем создать какую-нибудь функцию и применять ее:

function sqrt(n) { return n*n; }
sqrt(5)

Консольный вывод:

test> function sqrt(n) { return n*n; }
[Function: sqrt]
test> sqrt(5)
25
test>

И подобные функции и выражения JavaScript мы можем применять в запросах к БД. Например, найдем все документы, где поле age равно sqrt(5)+3:

test> db.users.find({age: sqrt(5)+3})
[
  {
    _id: ObjectId("62e2d6a5e75ce6a476c170b3"),
    name: 'Tom',
    age: 28,
    languages: [ 'english', 'spanish' ]
  },
  { _id: ObjectId("62e2d76ae75ce6a476c170b6"), name: 'Tomas', age: 28 },
  { _id: ObjectId("62e2d799e75ce6a476c170b7"), name: 'Tom', age: 28 },
  {
    _id: ObjectId("62e39da1c881653067e87900"),
    name: 'Bob',
    age: 28
  }
]
test>

Использование регулярных выражений

Еще одной замечательной возможностью при построении запросов является использование регулярных выражений. Например, найдем все документы, в которых значение ключа name начинается с буквы B:

db.users.find({name:/^B\w+/i})

Примерный консольный вывод:

test> db.users.find({name:/^B\w+/i})
[
  {
    _id: ObjectId("62e2d6a5e75ce6a476c170b4"),
    name: 'Bill',
    age: 32,
    languages: [ 'english', 'french' ]
  },
  {
    _id: ObjectId("62e39da1c881653067e87900"),
    name: 'Bob',
    age: 28
  }
]
test>

Поиск одиночного документа

Если все документы извлекаются функцией find, то одиночный документ извлекается функцией findOne

Например, выберем один элемент с name="Tom":

test> db.users.findOne({name: "Tom"})
{
  _id: ObjectId("62e2d6a5e75ce6a476c170b3"),
  name: 'Tom',
  age: 28,
  languages: [ 'english', 'spanish' ]
}
test>

Курсоры

Результат выборки, получаемой с помощью функции find, называется курсором. При необходимости мы можем передать курсор в отдельную переменную:

var cursor = db.users.find()

Курсоры инкапсулируют в себе наборы получаемых из бд объектов. Используя синтаксис языка javascript и методы курсоров, мы можем вывести полученные документы на экран и как-то их обработать. Например:

var cursor = db.users.find()

while(cursor.hasNext()){
  obj = cursor.next();
  print(obj["name"]);
}

Курсор обладает методом hasNext, который показывает при переборе, имеется ли еще в наборе документ. А метод next извлекает текущий документ и перемещает курсор к следующему документу в наборе. В итоге в переменной obj оказывается документ, к полям которого мы можем получить доступ.

test> var cursor = db.users.find()

test> while(cursor.hasNext()){
...   obj = cursor.next();
...   print(obj["name"]);
... }
Tom
Bob
Sam

test>

Также для перебора документов в курсоре в качестве альтернативы мы можем использовать конструкцию итератора javascript - forEach:

var cursor = db.users.find()
cursor.forEach(function(obj){
  print(obj.name);
})
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850