МДК.04.01 · ЗАНЯТИЕ 12 АКАДЕМИЧЕСКИХ ЧАСА

MongoDB: документ,
BSON и первая коллекция

Стенд
MongoDB 7 + MongoDB Compass 1.50
Данные
резюме соискателей: девять документов в коллекции hh.resumes
Работа руками
поднять сервер, создать базу, вставить документ, собрать пять запросов
Сдать
скриншот коллекции, файл запросов и README запуска

нажмите любую клавишу, чтобы начать ▸

01/35

Раздел 1 · MongoDB · занятие 1 из 5

Документ, BSON
и первая коллекция

Сегодня мы поднимаем сервер MongoDB, подключаемся к нему из Compass, создаём базу и коллекцию, кладём туда первый документ и учимся его находить. Реляционные базы вы уже знаете — тем интереснее посмотреть, что меняется, когда запись перестаёт быть строкой в таблице.

90 минутлаборатория9 документов5 запросов
01

С чего начинаем · одна анкета

Одно резюме: слева — то, как вы его хранили, справа — то, как оно выглядит целиком

resumeid · fio · position · city · salary
educationresume_id · level · place · year
jobresume_id · company · role · months
job_stackjob_id · tech
skillresume_id · name
contactresume_id · kind · value
→то же самое
hh.resumes · один документ697 байт
{
  fio: "Алина Дроздова",
  position: "Аналитик данных",
  city: "Москва",  salary: 120000,
  skills: ["SQL", "Python", "ClickHouse", "Power BI"],
  education: { level: "Высшее", year: 2024 },
  experience: [
    { company: "Ozon", months: 14, stack: ["ClickHouse"] },
    { company: "Retail Lab", months: 5, stack: ["SQL"] }
  ],
  contacts: { email: "a.drozdova@example.ru" }
}

Слева анкета разложена по шести таблицам — так её описывают в реляционной модели, и так вы делали на третьем курсе. Справа тот же человек лежит одним объектом. Ни один из вариантов не «правильный»: у каждого своя цена, и сегодня мы разберём, из чего эта цена складывается.

02

Зачем вообще нужна вторая модель

Цена сборки карточки и цена её изменения

шесть таблиц Открыть карточку — пять соединений

Чтобы показать резюме на экране, приложение забирает строку из resume и подтягивает к ней навыки, места работы, стек каждого места, образование и контакты. Пять JOIN ради одной анкеты, и так на каждое открытие.

Зато поменять название компании во всей базе можно одной строкой: оно лежит в одном месте.

сильная сторона: связи и целостность
один документ Открыть карточку — одно обращение

Всё, что показывается вместе, лежит вместе. База отдаёт готовый объект, приложению не нужно склеивать его из шести кусков.

Зато цена изменения другая: если название компании продублировано в двухстах резюме, менять придётся все двести. Ведь копия здесь не ошибка, а осознанное решение.

сильная сторона: чтение целиком
Правило, к которому мы будем возвращаться весь раздел: документ — это то, что кладут и достают целиком. Не то, что удобно нарисовать на схеме, а то, что читается и меняется одной операцией.
03

Определение · инструмент

Что такое MongoDB

MongoDB — документная система управления базами данных. Она хранит записи не строками в таблицах с заранее объявленными столбцами, а документами: самостоятельными объектами из пар «поле — значение», у каждого из которых своя структура. Документы группируются в коллекции, коллекции — в базы данных. Обращения к данным идут не на SQL, а через методы драйвера или оболочки: find, insertOne, updateOne, deleteOne.

«MongoDB is a document database designed for ease of application development and scaling. MongoDB stores data records as BSON documents. BSON is a binary representation of JSON documents, though it contains more data types than JSON.»

MongoDB Manual · Documents / What is MongoDB
чем не является Не замена реляционной базе

В нашей платформе источником истины остаётся PostgreSQL. MongoDB берёт на себя тот участок, где данные читаются и меняются целым объектом.

без схемы? Схема есть, просто она не в базе

Сервер не требует объявлять поля заранее, поэтому в одной коллекции спокойно лежат документы разной формы. Схема при этом никуда не девается — она переезжает в код приложения. На занятии 3 мы вернём часть проверок в базу.

чем управляем сегодня Сервер, оболочка и GUI

mongod — сам сервер, mongosh — консольная оболочка, Compass — графический клиент. Сегодня работаем через Compass, потому что в нём видно и данные, и типы, и результат запроса сразу.

04

Определения · что внутри чего

Сервер держит базы, база — коллекции, коллекция — документы

сервер mongodb://localhost:27017один процесс mongod
база данных hhеё создаём мы
коллекция resumes9 документов
{ }{ }{ }{ }{ }{ }{ }{ }{ } каждый документ — одно резюме,
зелёный — тот, что вставим руками

полное имя коллекции пишется через точку: hh.resumes — так она называется и в Compass, и в командах оболочки

adminconfiglocal Ещё три базы на том же сервере. Их создал сам сервер, и своих данных мы туда не кладём — разберём их на экране 16.
database · база данных Именованный контейнер коллекций

У каждой базы своё имя и свой набор файлов на диске. Данные разных баз не пересекаются.

аналог в PostgreSQL: база данных
collection · коллекция Именованная группа документов

Коллекция не описывает форму того, что в неё положат: она просто хранит документы под общим именем.

аналог в PostgreSQL: таблица
document · документ Единица данных

Набор пар «поле — значение», у каждого обязательно есть поле _id. Один документ — одно резюме.

аналог в PostgreSQL: строка

«MongoDB stores documents in collections. Collections are analogous to tables in relational databases. If a collection does not exist, MongoDB creates the collection when you first store data for that collection.»

MongoDB Manual · Databases and Collections — последнее предложение пригодится через десять минут: коллекция возникает в момент первой записи
05

Определение · документ

Документ: пары «поле — значение», где значением может быть другой документ

«A document is the basic unit of data in MongoDB. MongoDB documents are composed of field-and-value pairs… The value of a field can be any of the BSON data types, including other documents, arrays, and arrays of documents.»

MongoDB Manual · Documents · Document Structure
структура документаиз документации
{
   field1: value1,
   field2: value2,
   ...
   fieldN: valueN
}

Три следствия, которые видно уже на нашем резюме.

  • 1
    Значение — объектeducation хранит внутри себя level, place и year. Отдельная таблица для этого не нужна.
  • 2
    Значение — массивskills — это список строк прямо в документе, а не пять строк в таблице связи.
  • 3
    Значение — массив объектовexperience — список мест работы, у каждого свои поля и свой вложенный stack. Вложенность в вложенности здесь обычное дело.

Имена полей — строки. Имя _id зарезервировано под первичный ключ: оно уникально в пределах коллекции и не меняется.

06

Определение · формат хранения

BSON: не текст, а двоичная запись документа

На экране Compass документ выглядит как JSON, но на диске и в сети он лежит по-другому. BSON (Binary JSON) — двоичный формат представления документов. Каждое значение в нём записано с явным указанием типа и длины, поэтому серверу не нужно разбирать текст, чтобы понять, где заканчивается одно поле и начинается следующее.

«BSON is a binary serialization format used to store documents and make remote procedure calls in MongoDB. The BSON specification is located at bsonspec.org. BSON is a binary representation of JSON documents, though it contains more data types than JSON.»

MongoDB Manual · BSON Types
зачем двоичный Читается без разбора текста

Длина документа записана в первых четырёх байтах, длина каждой строки — перед самой строкой. Чтобы пропустить поле, достаточно прибавить число к смещению.

зачем типы Числа остаются числами

В JSON 65000 и "65000" различаются, а 2026-09-01 вообще не отличить от строки. В BSON есть отдельные типы для 32-битного целого, 64-битного целого, даты и двоичных данных.

чем платим Размер больше, чем у текста

Служебные байты длины и типа тоже занимают место. Наш первый документ — 183 байта, развёрнутое резюме Дроздовой — 697 байт. Числа получены запросом $bsonSize на нашем же стенде.

07

Разовый приём · документ по байтам

Один документ { n: "Пётр" } — 21 байт

15000000 02 6E00 09000000 D09FD191D182D18000 00
4 байта · длинаВесь документ занимает 0x15 = 21 байт. Число записано младшим байтом вперёд.
1 байт · тип0x02 — строка. У каждого типа свой номер: 1 — double, 2 — string, 8 — bool, 9 — date, 16 — int32.
2 байта · имя поля6E — латинская n, затем нулевой байт как признак конца имени.
13 байт · значениеСначала длина строки вместе с нулём — 9, затем «Пётр» в UTF-8: каждая кириллическая буква занимает два байта.
1 байт · конецНулевой байт закрывает документ. По нему сервер понимает, что полей больше нет.
docker exec -it hh-mongo mongosh hh
hh> db.aggregate([
     { $documents: [ { n: "Пётр" }, { a: 1 } ] },
     { $project: { doc: "$$ROOT",
                  size: { $bsonSize: "$$ROOT" } } }
   ])

[ { doc: { n: 'Пётр' }, size: 21 },
  { doc: { a: 1 },      size: 12 } ]

Пересчитайте сами: 4 + 1 + 2 + 4 + 9 + 1 = 21. Столько же вернул и сервер — вывод слева снят на нашем стенде, а не переписан из документации.

У документа { a: 1 } получается 12 байт: имя поля на байт короче, тип другой — 0x10, целое число, и значение занимает 4 байта вместо девяти.

Оператор $bsonSize считает размер документа в байтах и работает в конвейере агрегации. $$ROOT — это весь документ целиком; $documents позволяет посчитать то, чего в базе ещё нет. Тем же запросом по коллекции получаются 183 байта у резюме Беловой и 697 у Дроздовой — самое короткое и самое длинное из девяти.

08

Справка · типы, которые встретятся сегодня

Типы BSON: номер, псевдоним и где мы его увидим

Тип№Где в нашей коллекции
String2fio, city, position — текст в двойных кавычках
Object3education, contacts — вложенный документ
Array4skills, experience — список значений или объектов
ObjectId7_id — идентификатор, который база ставит сама
Boolean8ready_to_move — true или false
Date9updated — момент времени, а не строка с датой
Null10поле есть, но значения нет — это не то же, что поля нет вовсе
32-bit integer16salary, year, months — целые числа
Таблица типов BSON в документации MongoDB
mongodb.com/docs · Reference · BSON Types — полный список из 19 типов

Тип важен не сам по себе, а потому что от него зависит сравнение. Запрос { salary: { $gt: 100000 } } найдёт числа и пропустит строку "120000", даже если она выглядит как число. Это самая частая причина «запрос ничего не вернул, хотя данные есть».

09

Определение · первичный ключ

Поле _id и 12 байт ObjectId

Мы не писали _id, когда вставляли первый документ, а он появился. Так и задумано: если поле не передали, драйвер или сервер подставляет значение типа ObjectId. Это 12 байт, у которых есть внутренняя структура — и по ним можно узнать, когда документ создан.

6a9e467a 4831d3c4cf a42092
4 байта · времяСекунды с 1 января 1970 года. 0x6a9e467a = 1 788 757 626, то есть 7 сентября 2026 года, 05:07:06 UTC — момент, когда мы вставили резюме Беловой.
5 байт · процессСлучайное значение, одно на процесс клиента. Оно разное на разных машинах, поэтому два клиента не столкнутся идентификаторами.
3 байта · счётчикУвеличивается на каждый новый ObjectId внутри процесса. Он и разводит документы, созданные в одну и ту же секунду.

«The 12-byte ObjectId consists of: a 4-byte timestamp, representing the ObjectId's creation, measured in seconds since the Unix epoch; a 5-byte random value generated once per client-side process; a 3-byte incrementing counter, initialized to a random value.»

MongoDB Manual · mongosh Methods · ObjectId()
docker exec -it hh-mongo mongosh hh
hh> const d = db.resumes.findOne({ fio: "Анна Белова" })
hh> d._id.toString()
'6a9e467a4831d3c4cfa42092'
hh> d._id.getTimestamp()
ISODate('2026-09-07T05:07:06.000Z')

Первые четыре байта идентификатора и дата в выводе — одно и то же число, записанное двумя способами. Отсюда полезное следствие: сортировка по _id почти совпадает с сортировкой по времени создания. Но полагаться на это как на точное время не стоит — секунды ставит клиент, а не сервер, и часы на машине студента могут отставать.

10

Заход · что именно мы ставим

Сервер и клиент — это две разные программы

Здесь чаще всего и путаются: «скачал MongoDB» может означать и то, и другое. Сервер хранит данные и отвечает на запросы, клиент — рисует окно и эти запросы отправляет. Без сервера клиенту не к чему подключаться, а сервер прекрасно работает и без всякого окна.

сервер · mongod Держит данные и слушает порт 27017

Сервер занятия уже запущен и ждёт подключения на порту 27017. У всей группы он один и тот же — MongoDB 7, поэтому и кадры, и числа у нас совпадут. Сегодня мы к нему только подключаемся.

ставится один раз на весь раздел
клиент · MongoDB Compass Показывает данные, типы и результат запроса

Отдельное приложение с сайта mongodb.com. Оно ничего не хранит: закроете Compass — данные останутся на сервере. Кроме него есть консольная оболочка mongosh, к ней мы придём на занятии 2.

ставится на свою машину
1 · скачать Compass2 · подключиться3 · создать базу4 · вставить документ5 · найти документ
11

Шаг 1 из 5 · скачивание

Скачиваем MongoDB Compass

Страница загрузки MongoDB Compass на сайте mongodb.com
mongodb.com/try/download/compass · выбираем версию, платформу и тип пакета
  • 1
    VersionБерём верхнюю, она же последняя стабильная. У нас на кадрах — 1.50.0.
  • 2
    PlatformmacOS с процессором Apple выбирает macOS arm64, обычный ноутбук на Windows — Windows 64-bit.
  • 3
    PackageТри варианта: Compass — полная версия, Readonly — только чтение, Isolated — без сетевых запросов наружу. Нам нужна полная.
Регистрация не нужна. Если страница просит завести аккаунт — это раздел Atlas, облачного сервиса. Нам он сегодня не нужен: сервер мы поднимаем у себя.
1 · скачан2 · подключиться3 · создать базу4 · вставить документ5 · найти документ
12

Шаг 2 из 5 · подключение

Открываем Compass и подключаемся строкой mongodb://localhost:27017

Окно New Connection в MongoDB Compass со строкой подключения
Compass 1.50 · New Connection — поле URI уже заполнено значением по умолчанию

Строка подключения разбирается на четыре части, и каждая отвечает за своё.

  • 1
    mongodb://Схема: по ней клиент понимает, каким протоколом говорить. У облачного Atlas схема другая — mongodb+srv://.
  • 2
    localhostАдрес сервера. Контейнер пробросил порт на нашу же машину, поэтому адрес локальный.
  • 3
    27017Порт MongoDB по умолчанию. Если сервер занятия слушает другой порт, пишем в строке его — остальное в ней не меняется.
  • 4
    NameИмя соединения — только для нас, на сервер оно не уходит. Пишем «Стенд занятия», чтобы через месяц не гадать, что это за адрес.

Логина и пароля в строке нет: сервер поднят без проверки подлинности. Для учебного стенда на своей машине это допустимо, и мы к этому вернёмся в разделе о защите — там пустой пароль станет отдельной темой разговора.

13

Отказ · читаем сообщение целиком

Compass пишет ECONNREFUSED — и это хорошая новость

Ошибка подключения в Compass: connect ECONNREFUSED 127.0.0.1:27017
Настоящий кадр: сервер был остановлен, Compass честно сообщает причину
что означает Адрес есть, слушать некому

Соединение отклонено на уровне операционной системы: по адресу 127.0.0.1:27017 никто не отвечает. То есть Compass дошёл до нужной машины, но программы на порту нет.

что делать Проверить сервер, а не строку

Строка подключения тут ни при чём: её Compass разобрал и дошёл до адреса. Проверяем, работает ли сам сервер, и подключаемся заново. У нас на паре так и вышло: сервер остановился, пока мы читали теорию.

чем отличается от других Три сообщения — три разные причины

ECONNREFUSED — сервер не запущен. Server selection timed out — адрес недоступен, чаще всего опечатка в имени хоста. Authentication failed — сервер есть, но не пускает: неверные логин или пароль.

14

Шаг 3 из 5 · подключились

Три базы, которых мы не создавали

Compass после подключения: в дереве видны базы admin, config и local
Compass · соединение установлено, слева — список баз сервера
  • 1
    adminСлужебная база сервера: пользователи, роли, административные команды. Своих данных мы туда не кладём.
  • 2
    configНастройки самого сервера. Нужна, когда база разложена по нескольким узлам.
  • 3
    localДанные, которые не уезжают на другие узлы: журнал операций и внутренние отметки.
Правило простое: эти три базы — хозяйство сервера. Учебные данные складываем в собственную базу, и создаём её сами на следующем шаге.
1 · скачан2 · подключились3 · создать базу4 · вставить документ5 · найти документ
15

Шаг 4 из 5 · база и коллекция

База hh и коллекция resumes создаются одним окном

Окно Create Database в Compass: имя базы hh и имя коллекции resumes
Compass · Create Database — имя коллекции здесь обязательно

Compass не даёт создать базу без коллекции — и это не каприз интерфейса, а свойство сервера.

«If a collection does not exist, MongoDB creates the collection when you first store data for that collection.»

MongoDB Manual · Databases and Collections

То есть база живёт ровно до тех пор, пока в ней что-то лежит. Пустая база, из которой удалили последнюю коллекцию, исчезает из списка сама.

Как называем. Имя базы — по системе, а не по студенту: hh, а не test2. Имя коллекции — во множественном числе и латиницей: resumes. Это соглашение, а не требование сервера, но именно оно потом бережёт время на review.

16

Разбор интерфейса · пустая коллекция

Пять мест в окне, которыми мы будем пользоваться весь раздел

Окно коллекции resumes в Compass до вставки документов 1 2 3 4 5
Compass · коллекция создана, документов пока ноль
  • 1
    Путьсоединение → база → коллекция: всегда видно, где вы находитесь
  • 2
    ВкладкиDocuments, Schema, Indexes, Validation — четыре разных взгляда на одну коллекцию
  • 3
    Строка запросасюда пишется фильтр; кнопка Options открывает сортировку и проекцию
  • 4
    ADD DATAвставить документ руками или загрузить файл JSON
  • 5
    Счётчик и видсколько документов нашлось и как их показать: список, JSON или таблица
17

Шаг 5 из 5 · первый документ

Пишем документ руками: ADD DATA → Insert document

Окно Insert Document в Compass с JSON первого резюме
Compass · Insert Document, режим {} — редактор JSON

Начинаем с маленького документа: пять полей, ни одного вложенного объекта. Так проще увидеть, что происходит после вставки.

что набираем183 байта
{
  "fio": "Анна Белова",
  "position": "Junior Python-разработчик",
  "city": "Ярославль",
  "salary": 65000,
  "skills": ["Python", "Git"]
}

Обратите внимание на 65000 без кавычек: мы кладём число, а не строку. Через десять минут именно от этого будет зависеть, найдёт ли резюме запрос со сравнением.

18

Результат · документ в коллекции

Полей стало шесть: _id база поставила сама

Первый документ в коллекции resumes: видно поле _id типа ObjectId
Compass · один документ, счётчик показывает 1 – 1 of 1
  • 1
    _id: ObjectId('6a9e467a…')Мы его не писали. Раз поле не передали — сервер подставил ObjectId, и по нему теперь можно узнать время вставки.
  • 2
    skills: Array (2)Compass не разворачивает массив сразу, а показывает тип и длину. Треугольник слева раскрывает содержимое.
  • 3
    Цвет значенияСтроки зелёные, числа синие, ObjectId красный. Это подсказка о типе, а не оформление: увидев 65000 зелёным, вы сразу поймёте, что число сохранилось строкой.
Проверьте на своей коллекции: раскройте skills и убедитесь, что элементы нумеруются с нуля — 0: "Python", 1: "Git". Индекс элемента понадобится нам в запросах.
1 · скачан2 · подключились3 · база создана4 · документ вставлен5 · найти документ
19

Готовые данные · загрузка файла

Восемь резюме одним файлом: ADD DATA → Import JSON or CSV file

Меню ADD DATA в Compass с пунктами импорта файла и вставки документа
Compass · у кнопки ADD DATA два пункта: файл и один документ
  • 1
    Выбираем файлstend/seed/resumes.json из репозитория занятия. Внутри — массив из восьми документов.
  • 2
    Формат — JSONCompass определяет его сам. Даты записаны в расширенном виде {"$date": "2026-09-03T14:40:00Z"}, поэтому они попадут в базу типом Date, а не строкой.
  • 3
    Жмём ImportСчётчик становится 1 – 9 of 9: наш документ плюс восемь загруженных.

Файл лежит в репозитории неспроста: у всей группы одинаковые данные, поэтому и результаты запросов у всех совпадут. Если счётчик показал не девять — импорт прошёл дважды, и коллекцию нужно очистить и повторить.

20

Что видно на девяти документах

Одна коллекция — документы разной формы

Табличный вид коллекции resumes в Compass: девять документов и типы в шапке
Compass · табличный вид: в шапке столбца стоит тип — _id ObjectId, fio String, salary Int32
у Беловой Нет полей education и updated

Мы вставили её первой, с пятью полями. Сервер не возразил: коллекция ничего не требует.

у Дроздовой Есть portfolio, которого нет у остальных

Поле появилось только там, где оно осмысленно. В таблице для этого понадобился бы столбец со значением NULL у всех прочих.

у Нечаевой experience — пустой массив, зато есть courses

Опыта нет, но есть курсы. Форма документа отражает жизнь человека, а не общий шаблон.

У этой свободы есть обратная сторона: пока форму никто не проверяет, в коллекцию так же спокойно ляжет резюме с полем salaryy или зарплатой строкой. Проверки мы включим на занятии 3, когда разберём schema validation.

21

Граница агрегата · один документ целиком

Резюме, развёрнутое до последнего уровня

Развёрнутый документ резюме в Compass со всеми вложенными полями
Compass · кнопка Expand all раскрывает вложенные объекты и массивы

Здесь видно, ради чего всё затевалось. Одним обращением база отдала то, что в реляционной схеме лежало в шести таблицах.

  • 1
    education — объектУровень, учебное заведение и год лежат внутри резюме. Отдельно от человека они не нужны.
  • 2
    experience — массив объектовДва места работы, у каждого свой stack — массив внутри объекта внутри массива.
  • 3
    updated — ISODateCompass показывает и машинное значение, и человеческое: «September 3, 2026 at 2:40:00 PM UTC».
Вопрос, на который отвечает занятие 2: а если у человека сто мест работы — держать их все внутри резюме? Там мы будем выбирать между вложением и ссылкой и оформлять решение как ADR.
22

Определение · запрос

Фильтр — это тоже документ

В SQL запрос написан на отдельном языке: SELECT … WHERE city = 'Ярославль'. В MongoDB запрос — это такой же объект из пар «поле — значение», что и данные. Мы описываем документом, каким должен быть искомый документ, и сервер возвращает все, которые под описание подходят.

форма { поле: значение }

Простейший фильтр: найти всё, где поле равно значению. Пустой фильтр {} означает «без условий» — вернутся все документы коллекции.

оператор { поле: { $оператор: значение } }

Когда нужно не равенство, значение заменяется вложенным документом с оператором: $gt — больше, $lt — меньше, $in — входит в список, $exists — поле есть.

несколько условий { поле1: …, поле2: … }

Два поля в одном фильтре соединяются по «и». Отдельный $and для этого не нужен — он пригодится только там, где условия относятся к одному и тому же полю.

Где это набирать: строка запроса на вкладке Documents. Кнопка Find выполняет фильтр, Reset очищает, Options открывает сортировку, проекцию и ограничение количества.
23

Запрос 1 из 5 · точное совпадение

{ city: "Ярославль" } — 5 документов из 9

Результат запроса по городу в Compass: пять документов
Compass · счётчик показывает 1 – 5 of 5

Самая частая форма запроса и самая частая причина пустого результата.

  • 1
    Значение сравнивается целиком«Ярославль» не найдёт «г. Ярославль» и не найдёт «ярославль». Поиск по части строки — это отдельный оператор $regex, и он работает медленнее.
  • 2
    Тип тоже сравнивается{ salary: 65000 } не найдёт документ, где зарплата сохранена строкой "65000". Число и строка — разные значения.
  • 3
    Кавычки обязательныСтрока пишется в кавычках, число — без. Через два экрана мы посмотрим, что будет, если про это забыть.
24

Запросы 2 и 3 из 5 · вглубь документа

Точка идёт внутрь объекта, а массив ищется по элементу

Запрос по вложенному полю education.level в Compass
{ "education.level": "СПО" } → 4 документа
Запрос по элементу массива skills в Compass
{ skills: "MongoDB" } → 2 документа
вложенное поле Путь через точку, всё вместе в кавычках

Запись "education.level" означает «поле level внутри объекта education». Кавычки нужны, потому что точка внутри имени иначе читается как обращение к свойству. Глубина не ограничена: "experience.0.stack" добирается до стека первого места работы.

массив Условие проверяется для каждого элемента

{ skills: "MongoDB" } читается не как «массив равен строке», а как «среди элементов массива есть такой». Ни $in, ни индекс элемента для этого не нужны — и это, пожалуй, самое неожиданное правило для того, кто пришёл из SQL.

25

Запрос 4 из 5 · сравнение, сортировка, проекция

Кто просит больше 100 000 — по убыванию и только два поля

Запрос с оператором сравнения, сортировкой и проекцией в Compass
Compass · панель Options: Project, Sort, Limit — всё, что в SQL пишется в одном запросе
  • 1
    Filter: { salary: { $gt: 100000 } }Оператор $gt — строго больше. Есть и $gte, $lt, $lte, $ne.
  • 2
    Project: { fio: 1, salary: 1, _id: 0 }Единица — «показать поле», ноль — «убрать». Поле _id возвращается всегда, если его не выключить явно.
  • 3
    Sort: { salary: -1 }Минус единица — по убыванию, единица — по возрастанию. Самойлов со 150 000 оказывается первым.

Проекция — это не украшение. Она уменьшает то, что сервер собирает и передаёт по сети, и на больших документах разница заметна. Когда мы дойдём до производительности, это будет первым, что мы проверяем в медленном запросе.

26

Запрос 5 из 5 · есть ли поле

{ portfolio: { $exists: true } } — вопрос, которого нет в SQL

Запрос с оператором $exists в Compass: два документа с полем portfolio
Compass · два резюме из девяти содержат поле portfolio

В таблице столбец есть у всех строк, вопрос стоит иначе: пустое значение или нет. В коллекции поле может просто отсутствовать, и это третье состояние.

поля нет { portfolio: { $exists: false } }

Семь резюме, где ссылки на портфолио никто не заполнял.

поле есть, значение пустое { portfolio: null }

Осторожно: этот фильтр находит и документы, где поля нет вовсе. Чтобы разделить два случая, условия придётся соединить.

$exists — рабочий инструмент, когда коллекция копилась годами и форма документов менялась. Он же первым показывает, что схема в коде и схема в базе разошлись.

27

Отказ · разбор ошибки

Строка без кавычек: кнопка Find гаснет

Compass подсвечивает красным неправильный фильтр без кавычек
Настоящий кадр: { city: Ярославль } — рамка красная, Find недоступна
что произошло Запрос даже не ушёл на сервер

Compass разбирает фильтр у себя, и Ярославль без кавычек для него — имя переменной, а не строка. Разбор не удался, поэтому кнопка отключилась, а список документов остался прежним.

чем это отличается от пустого результата Ноль документов — тоже ответ

Если фильтр разобрался, но ничего не нашёл, счётчик покажет 0 – 0 of 0, а рамка останется обычной. Красная рамка означает ошибку записи, пустой список — ошибку в данных или в условии.

привычка Смотреть на счётчик, а не на экран

Строка 1 – 5 of 5 — единственное честное подтверждение, что запрос выполнен и вернул именно столько. Скриншот со счётчиком мы и просим приложить к работе.

28

Справка · пять фильтров на одном экране

Что писать и сколько должно найтись

{ city: "Ярославль" }5 из 9

Точное совпадение строки. Регистр и лишние пробелы значение меняют.

{ "education.level": "СПО" }4 из 9

Путь внутрь вложенного объекта через точку. Всё имя — в кавычках.

{ skills: "MongoDB" }2 из 9

Условие проверяется для каждого элемента массива. Индекс указывать не нужно.

{ salary: { $gt: 100000 } }4 из 9

Оператор сравнения. Работает только с числами — строка "120000" не найдётся.

{ portfolio: { $exists: true } }2 из 9

Наличие поля. Отличается и от null, и от пустой строки.

{ city: Ярославль }ошибка

Строка без кавычек. Фильтр не разобрался, запрос на сервер не ушёл.

Числа в средней колонке — результат прогона на нашем стенде. Если у вас получилось другое, расходятся не запросы, а данные: проверьте, что импорт прошёл ровно один раз и в коллекции девять документов.

29

Две вкладки, которые пригодятся дальше

Что Compass знает о коллекции без нашего описания

Вкладка Schema в Compass: типы полей и распределение значений
Schema · кнопка Analyze строит отчёт по выборке документов
Вкладка Indexes в Compass: единственный индекс _id_
Indexes · в коллекции один индекс — _id_, его создал сервер
Schema Схема, восстановленная по данным

Compass берёт выборку документов и показывает, какие поля встречаются, каких типов и как распределены значения. У city сразу видно, что Ярославль занимает большую часть, а у courses — что поле есть далеко не везде. Это отчёт по факту, а не описание схемы: сервер такой схемы не хранит.

Indexes Единственный индекс создан не нами

Индекс _id_ сервер создаёт вместе с коллекцией, и удалить его нельзя. Все наши сегодняшние запросы шли без индексов — на девяти документах это незаметно. На занятии 4 мы посмотрим тот же запрос на выборке побольше и научимся читать план его выполнения.

30

Работа руками · 25 минут

Что нужно сделать до конца пары

  1. 1Подключиться из Compass строкой mongodb://localhost:27017 и увидеть список баз.кадр со списком баз
  2. 2Создать базу hh и коллекцию resumes, вставить своё резюме вручную: не меньше пяти полей, из них один массив.кадр документа
  3. 3Загрузить stend/seed/resumes.json и убедиться, что счётчик показывает 1 – 9 of 9: восемь загруженных плюс ваш документ.кадр счётчика
  4. 4Собрать пять запросов из свода и записать в файл queries.md фильтр и число найденных документов.queries.md
  5. 5Сломать один запрос намеренно и записать, чем отличается ошибка разбора от пустого результата.абзац в queries.md
  6. 6Написать README.md: как подключиться из Compass, как загрузить данные и как удалить коллекцию.README.md
Приёмка: вы показываете коллекцию на своём экране и объясняете любой из пяти запросов — что он ищет и почему нашёл именно столько. Скриншот без живой коллекции не принимается: со следующего занятия мы дописываем в неё же.
31

Итог занятия

Коллекция, которую вы можете поднять заново

За 90 минут мы прошли путь от пустого Compass до коллекции с данными и запросами: поставили клиент, подключились к серверу, создали базу, положили документ, нашли его пятью способами и посмотрели, что бывает, когда фильтр записан неверно.

9документов в коллекции 5рабочих запросов 21байт в разобранном документе 1индекс, созданный сервером

Дальше по разделу: занятие 2 — вложение против ссылки и первое ADR; занятие 3 — проверка формы документа средствами базы; занятие 4 — индексы и план запроса; занятие 5 — агрегация и повторяемая миграция документов.

Мем: котёнок у двух мониторов, «ало офис, да да документы»
32

Домашнее задание · к следующему занятию

Максим Николаевич не хочет задавать домашнее задание. Но очень хочет

  1. 1
    Своя коллекция на своей предметной области

    Возьмите не резюме, а что-то из своего проекта: карточку заказа, тикет, объявление. Спроектируйте документ и положите в новую коллекцию пять таких документов. Хотя бы у двух форма должна отличаться — лишнее поле или отсутствующее.

  2. 2
    Пять запросов и один сломанный

    К своей коллекции соберите те же пять видов фильтров: точное совпадение, вложенное поле, элемент массива, сравнение и $exists. Шестым запишите намеренно неверный и объясните, ошибка это разбора или пустой результат.

  3. 3
    Абзац о цене

    Опишите, что в вашем документе продублировано и во что обойдётся изменение этого значения. Без формулировок из документации: своими словами и на своих данных.

Мем: котёнок у двух мониторов, «ало офис, да да документы»
да да документы
ДЗ

Домашнее задание · порядок сдачи

Как сдаём

Что сдаём

Папка lesson-01/: README.md, queries.md, файл данных seed.json и скриншот коллекции со счётчиком.

Ветка и PR

Ветка hw-01, коммит с содержательным сообщением, Pull Request в собственную main. Merge делаете сами после проверки.

Срок

До начала занятия 2. После срока работа принимается, но разбирается уже не на паре, а в чате.

Про ИИ

Модель можно просить причесать формулировки и оформить .md — я сам так делаю всегда, поэтому и вам запрещать не буду. А вот запросы должны быть выполнены в вашей коллекции: числа в queries.md сверяются с ней.

Критерий приёмки: по вашему же README на чужой машине коллекция собирается заново: Compass подключается, данные заливаются из вашего файла, а все шесть запросов возвращают ровно те числа, которые записаны.

В диалоге печати снимите галочку «Колонтитулы», иначе браузер допишет дату и адрес страницы.

ДЗ

МДК.04.01 · Технология разработки и защиты баз данных · 4 курс

Домашнее задание № 1

Занятие 1 — MongoDB: документ, BSON и первая коллекция

hw-01

Максим Николаевич не хочет задавать вам домашнее задание. Но очень хочет.

Мем: ало офис, да да документы

Что сделать

  1. Своя коллекция. Возьмите предметную область из своего проекта — карточку заказа, тикет, объявление. Спроектируйте документ и положите в новую коллекцию пять таких документов. Минимум у двух форма должна отличаться: лишнее поле или отсутствующее.
  2. Пять запросов. Соберите к своей коллекции пять видов фильтров: точное совпадение, вложенное поле через точку, элемент массива, оператор сравнения и $exists. Для каждого запишите сам фильтр и число найденных документов.
  3. Один сломанный запрос. Шестым запишите намеренно неверный фильтр и объясните, что произошло: ошибка разбора (красная рамка, запрос не ушёл на сервер) или пустой результат (счётчик 0 – 0 of 0).
  4. Абзац о цене. Опишите своими словами, что в вашем документе продублировано и во что обойдётся изменение этого значения, если документов станет двести.

Числа в queries.md сверяются с вашей коллекцией на приёмке. Скриншот без живой коллекции не принимается: со следующего занятия мы дописываем в эту же базу.

Порядок сдачи

Что сдаёмПапка lesson-01/: README.md, queries.md, файл данных seed.json и скриншот коллекции со счётчиком найденных документов.
Ветка и PRВетка hw-01, коммит с содержательным сообщением, затем Pull Request в свою main с коротким описанием: какая предметная область и чем отличаются формы документов. Merge делаете сами после проверки.
СрокДо начала занятия 2. После срока работа принимается, но разбирается в чате, а не на паре.
Про ИИМодель можно просить причесать формулировки и оформить .md — я сам так делаю всегда, поэтому и вам запрещать не буду. Запросы при этом должны быть выполнены в вашей коллекции.

Что должно получиться

README.md
как подключиться к серверу из Compass, как загрузить данные, как удалить коллекцию
queries.md
шесть фильтров, число найденных документов и абзац про сломанный запрос
seed.json
массив из пяти документов, который загружается через ADD DATA → Import JSON
скриншот
коллекция с видимым счётчиком и одним выполненным запросом

Файлы занятия — в папке lessons/02-mongodb-pervyy-dokument/stend/. Разбор запросов — в презентации занятия, экран 29. Вопросы по заданию — на паре или в чате группы.