Раздел 36 · MongoDB с нуля

Чтение и операторы запроса

junior~20 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке мы искали документ по номеру. Но покупатель приходит в магазин не с номером книги, а с вопросом: «есть что-нибудь из фантастики до 500 рублей?». Сегодня учимся задавать такие вопросы. Все примеры на учебной базе магазина.

Запрос по образцу

Представь, что ты ищешь в шкафу папку и описываешь её помощнику: «синяя, на корешке написано 2025». Ты не объясняешь, как искать, ты описываешь, что найти. Помощник сам переберёт полки.

Запрос в MongoDB устроен так же. Ты передаёшь в find документ-образец, фильтр, и база возвращает все документы, которые под него подходят:

db.books.findOne({ title: 'Шинель' })
{
  _id: 5,
  title: 'Шинель',
  genre: 'повесть',
  price: 250,
  pages: 64,
  year: 1842,
  author: { _id: 3, name: 'Гоголь', country: 'Россия' },
  tags: [ 'классика' ]
}

Методов чтения два:

  • findOne возвращает первый подходящий документ или null;
  • find возвращает все подходящие документы.

Документы бывают длинными, поэтому дальше в find будет второй аргумент: какие поля показать. Например, { title: 1, _id: 0 } значит «только название, без _id». Подробно о нём в следующем уроке, а пока читай его как «покажи название».

db.books.find({ genre: 'фантастика' }, { title: 1, _id: 0 })
[ { title: 'Пикник на обочине' }, { title: 'Трудно быть богом' } ]

Поле с конкретным значением в фильтре означает «равно». Если ничего не нашлось, mongosh промолчит: пустой результат он не печатает.

Операторы сравнения

«Равно» мало. Чтобы спросить «больше» или «меньше», вместо значения пишут документ с оператором. Операторы начинаются со знака доллара:

ОператорЗначитАналог в SQL
$eqравно=
$neне равно<>
$gt, $gteбольше, больше или равно>, >=
$lt, $lteменьше, меньше или равно<, <=
$in, $ninвходит в список, не входитIN, NOT IN

Книги дороже 600 рублей и книги от 400 до 600:

db.books.find({ price: { $gt: 600 } }, { title: 1, price: 1, _id: 0 })
db.books.find({ price: { $gte: 400, $lte: 600 } }, { title: 1, price: 1, _id: 0 })
[
  { title: 'Мастер и Маргарита', price: 690 },
  { title: 'Мёртвые души', price: 610 },
  { title: 'Грокаем алгоритмы', price: 1290 },
  { title: 'Совершенный код', price: 2490 }
]
[
  { title: 'Пикник на обочине', price: 450 },
  { title: 'Трудно быть богом', price: 520 }
]

Два оператора на одном поле в одном документе работают как «и»: так получается диапазон. Список значений задаёт $in:

db.books.find({ genre: { $in: ['повесть', 'учебник'] } }, { title: 1, genre: 1, _id: 0 })
[
  { title: 'Собачье сердце', genre: 'повесть' },
  { title: 'Шинель', genre: 'повесть' },
  { title: 'Грокаем алгоритмы', genre: 'учебник' },
  { title: 'Совершенный код', genre: 'учебник' },
  { title: 'Нос', genre: 'повесть' }
]

Тип значения важен. В базе цены это числа, поэтому { price: { $gt: '500' } } со строкой '500' не найдёт ни одной книги: MongoDB сравнивает значения одного типа и не превращает строку в число.

И, или

Несколько полей в фильтре соединяются через «и». Романы, написанные до 1900 года:

db.books.find({ genre: 'роман', year: { $lt: 1900 } }, { title: 1, _id: 0 })
[ { title: 'Мёртвые души' } ]

Для «или» есть оператор $or. Он принимает массив условий, и документ подходит, если выполнено хотя бы одно. Учебники или совсем короткие книги:

db.books.find(
  { $or: [{ genre: 'учебник' }, { pages: { $lt: 100 } }] },
  { title: 1, _id: 0 }
)
[
  { title: 'Шинель' },
  { title: 'Грокаем алгоритмы' },
  { title: 'Совершенный код' },
  { title: 'Нос' }
]

Есть и явный $and с таким же массивом. Он нужен редко: когда два условия на одно и то же поле нельзя уложить в один документ, например два $or.

урок из курса

Урок из курса «MongoDB с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.