В предыдущем посте мы узнали, как создать базу данных и коллекцию, а также начали работать с базой данных, используя операции CRUD для создания документов.
В конце заметки я рекомендовал использовать команду mongoimport
в инструментах базы данных для импорта большего набора данных, чтобы работать с MQL более сложным образом.
Если вы еще не сделали этого, я рекомендую вам перейти к пункту 3 и следовать инструкциям.
- CRUD-операции для чтения документов
- CRUD-операция findOne()
- Необязательные параметры findOne()
- Проекция запросов (Проекция)
- CRUD операция find()
- Ограничить курсор определенным количеством результатов в пакете
- Необязательные параметры find()
- Сложные запросы с операторами запросов
- Нахождение значения, эквивалентного прошлому в запросе: оператор $eq
- Найти значение, большее, чем переданное значение: оператор $gt
- Найдите все значения, отличные от: оператор $ne
- Сравните даты с помощью операторов сравнения
- Исключение результатов, содержащих значение в поле массива: оператор $nin.
- MQL в mongosh против работы с драйвером
CRUD-операции для чтения документов
Сегодня мы узнаем, как использовать MQL, язык запросов MongoDB, для запроса нашей базы данных redtattoo
.
Как мы узнали в предыдущем посте, мы собираемся использовать терминал для подключения к нашему локальному серверу и использовать нужную базу данных и коллекцию.
CRUD-операция findOne()
Первое, что мы собираемся сделать, это просмотреть любой документ в базе данных, произвольно, просто чтобы увидеть, какую структуру имеет документ.
Мы сделаем это, сначала запустив, как мы узнали ранее, show collections
, чтобы посмотреть, какие коллекции у нас доступны, и убедиться, что мы правильно импортировали данные, чтобы мы могли следовать указаниям в этом посте.
и затем запустить
db.artistas.findOne()
findOne()
возвращает первый найденный документ, удовлетворяющий заданному критерию запроса, т.е. первый документ из естественного порядка поиска документов. Если коллекция имеет какое-то ограничение (обычно в МБ), то естественный порядок соответствует порядку вставки. В данном случае мы видим, что возвращается тот, который соответствует artist_id: 743
, соответствующий name: "Alex Holt"
.
Необязательные параметры findOne()
Метод findOne() принимает два необязательных аргумента, передаваемых ему для определения этого критерия. Например, мы можем сказать
db.artistas.findOne(query, projection)
сам запрос и условие проекции.
Если мы посмотрим на изображение выше, то увидим, что для артиста id 743 свойство owns_studio
имеет значение Yes
. Мы можем попросить MongoDB вернуть первое в естественном порядке, так что значение будет No
.
db.artistas.findOne({ "owns_studio": "No"})
В этом случае, как мы видим, идентификатор исполнителя теперь 701
, соответствующий исполнителю name: "Sue King"
.
Проекция запросов (Проекция)
Но мы сказали, что этот метод также принимает второй дополнительный параметр, проекцию. Что это значит?
MongoDB всегда будет возвращать те поля в документе, которые являются проецируемыми. По умолчанию все поля проецируются, то есть имеют значение проекции 1 или true
.
1 или значения, отличные от 0 и true, указывают на включение в проекцию.
Однако, если мы явно проецируем поле, будет возвращено только это поле вместе со значением _id
, которое исключается, только если его значение проекции явно установлено на 0 или false
.
Рассмотрим пример
db.artistas.findOne({ "owns_studio": "No"}, {"owns_studio": 1, "name": 1})
Если мы хотим опустить значение поля _id
, мы должны явно передать 0 (или false
).
db.artistas.findOne({ "owns_studio": "No"}, {"owns_studio": 1, "name": 1, "_id": 0})
Мы рассмотрим Projection
позже в этой серии более подробно, поскольку существует много, много других способов проецирования, а также специальные способы для более сложных данных, таких как вложенные данные или массивы.
CRUD операция find()
До сих пор, когда мы просили MongoDB найти единицу, или findOne(), она всегда возвращала только единицу… Но что происходит, когда нам нужен список?
Затем мы должны запустить
db.artistas.find()
Но подождите… Что случилось, вернулись ли 1000 документов, которые мы импортировали в коллекцию?
Нет. Этот метод возвращает cursor
, который является ссылкой на набор результатов, возвращенный запросом, по которому можно выполнять итерации. То есть мы можем видеть больше, чем то, что находится в курсоре, а затем получить доступ к нужному нам документу.
По умолчанию курсор для find() показывает нам 101 результат, пока не превышен максимальный размер документа, который составляет 16MB (как мы видели в первой части серии), и один из способов получить больше — выполнить it
, как мы видим на изображении.
Мы также можем присвоить курсор переменной (помните, что мы находимся в полнофункциональном REPL!) и использовать некоторые из ее методов. Например.
let tatuadores = db.artistas.find({ "owns_studio": "Yes" });
while (tatuadores.hasNext()) {
printjson(tatuadores.next());
}
Здесь мы используем метод hasNext()
, который оценивает, есть ли еще документы, удовлетворяющие запросу, в курсоре, и мы используем метод next()
, чтобы перебирать их до тех пор, пока hasNext()
возвращает true
.
Другие методы курсора — forEach()
, toArray()
и objsLeftInBatch()
, который сообщает нам, сколько объектов находится в партии, после выполнения возвращенной итерации (или набора).
Мы также можем использовать метод isExhausted()
, чтобы проверить, что в курсоре действительно больше нет объектов или документов.
Напомним, что каждый документ сопоставляется с объектом.
Полный список методов курсора можно найти здесь.
При использовании find()
в ранних версиях консоли, вы использовали метод pretty()
, чтобы результаты в курсоре отображались отформатированными. В mongosh
по умолчанию выполняется pretty()
.
Давайте рассмотрим пример использования forEach()
:
let tatuadores = db.artistas.find({ "owns_studio": "Yes" });
tatuadores.forEach((tatuador) => {
if (tatuador.payment_method === "Credit Card Only") {
printjson(tatuador);
}
});
Ограничить курсор определенным количеством результатов в пакете
В очень большой базе данных, с очень маленькими размерами документов, мы можем получить слишком много возвращаемых объектов. Если мы хотим явно ограничить их для повышения производительности, мы можем использовать метод limit()
, например, так.
db.artistas.find({"payment_method" : "Credit Card Only"}).limit(5)
Более подробную информацию о методе limit()
можно найти здесь.
Необязательные параметры find()
Find также принимает конфигурацию двух необязательных параметров: запрос и проекция.
Сложные запросы с операторами запросов
Мы начнем выполнять более сложные запросы, используя операторы сравнения. В других записях мы изучим логические операторы, операторы элементов, оценки, массивов и геопространственные операторы. И, конечно, мы сделаем отдельный пост о проекции.
Давайте начнем!
Нахождение значения, эквивалентного прошлому в запросе: оператор $eq
Этот оператор позволяет нам запросить базу данных, чтобы найти все документы, которые имеют определенное значение, эквивалентное переданному. Например, мы собираемся искать всех художников, у которых нет собственной студии.
Мы всегда будем ограничивать количество запросов до 5, чтобы сократить время ответа, но это не является обязательным условием.
db.artistas.find({ "owns_studio": { $eq: "No" } }).limit(5)
Формат запроса следующий:
{ <campo>: { $eq: <valor> } }
Мы можем сказать, что это эквивалентно тому, чтобы сделать такой запрос
db.artistas.find({ "owns_studio": "No" }).limit(5)
Однако, используя операторы, мы можем комбинировать их или использовать логические операторы для более сложных запросов, как мы увидим по мере продвижения.
Найти значение, большее, чем переданное значение: оператор $gt
Этот оператор позволяет найти документы, для которых значение переданного поля больше заданного. В этом случае все художники с идентификатором больше 500
db.artistas.find({ "artist_id": { $gt: 500 } }).limit(5)
Формат запроса следующий:
{ <campo>: { $gt: <valor> } }
Аналогично мы можем найти значения больше или равные переданному значению с помощью $gte
, меньше с помощью $lt
, или меньше или равные переданному значению с помощью $lte
. Синтаксис такой же.
Найдите все значения, отличные от: оператор $ne
ne
означает not equal
, или not equal
. Мы используем его для поиска всех документов, значение которых не равно прошлому.
db.artistas.find({ "artist_id": { $ne: 500 } }).limit(5)
Конечно, мы не обязательно проводим численные сравнения. Мы сравниваем буквальные значения. Поэтому мы можем передать любой тип.
db.artistas.find({ "name": { $ne: "Cordelia Swanson" } }).limit(5)
Это справедливо и для приведенных выше сравнений. Например:
db.artistas.find({ "country": { $lt: "PE" } }).limit(5)
Где он вернет все значения меньше, чем «PE» в качестве кода страны, в алфавитном порядке.
Сравните даты с помощью операторов сравнения
Мы также можем использовать их для свиданий. Например, если мы хотим найти всех художников, которые присоединились к платформе год или более назад, мы сделаем это следующим образом:
db.artistas.find({ "joined_network": { $lte: new Date("2021-08-12") } }).limit(5)
Исключение результатов, содержащих значение в поле массива: оператор $nin
.
Этот оператор not in
, позволяет нам исключить объекты из курсора, если они содержат определенное значение в поле массива.
Например, допустим, мы хотим отфильтровать всех художников в стилях geometric
и realism
из нашего курсора результатов.
db.artistas.find({ "styles": { $nin: ["geometric", "realism"] } }).limit(10)
$nin
также можно использовать для исключения из курсора документов, не содержащих определенного поля.
Более подробную информацию об этом операторе условия можно найти в документации
MQL в mongosh против работы с драйвером
При написании приложения не путайте методы работы с MQL в консоли MongoDB с методами, предоставляемыми различными драйверами.
Многие из этих драйверов (или промежуточного ПО) создают уровни абстракции для упрощения комбинации операторов и могут предоставлять различные методы работы с базой данных.
В следующем посте мы будем использовать логические операторы — до тех пор!
Отдельное спасибо @wassimchegham, который всегда просматривает мои скриншоты, и @dfreniche, которого я попросил сделать рецензию, и он ответил «RIGHT NAO!»<3