Наиболее простой способом выборки документов из коллекции представляет использование функции find().
Действие этой функции во многом аналогично обычному запросу SELECT * FROM Table
, который применяется в SQL и который извлекает все строки. Например, чтобы извлечь все
документы из коллекции users, созданной в прошлой теме, мы можем использовать команду:
db.users.find()
Однако что, если нам надо получить не все документы, а только те, которые удовлетворяют определенному требованию. Например, мы ранее в базу добавили следующие документы:
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. Например, мы можем создать какую-нибудь функцию и применять ее:
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); })