Контрольная точка 01 · самостоятельная работа

Справочник по MongoDB · контрольная точка · после модуля 1

КТ-01

КТ-01

Инвентаризация
склада

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

Формат
Самостоятельно, без разбора
База
sandbox.warehouse — 21 позиция
Время
90 минут
Сдать
inventory.py и inventory.md
Сдать
inventory.cpp и inventory.md
Сдать
inventory.go и inventory.md
Сдать
inventory.rb и inventory.md

github.com/MaximBytecamp/mongodb-practice → kt01

В папке — задание, файл пересчёта stocktake.json и бланк отчёта report_template.md. Решения там нет и не будет: его разбирают на приёмке.

§1Ситуация

На складе провели пересчёт. Учётные остатки лежат в базе, результат пересчёта пришёл файлом. Нужно сверить одно с другим, привести учёт в порядок и написать отчёт, по которому решение примет заведующий складом — человек, который в базу не полезет.

ИсточникЧто этоПоля
sandbox.warehouseУчёт: сколько числитсяsku, title, category, qty_accounted, shelf
kt01/stocktake.jsonПересчёт: сколько нашли на полкахsku, counted, counted_by
PowerShellподготовка и запуск
docker compose run --rm reset          # учёт на 21 позицию
# без Docker: bash ../stend/load.sh в Git Bash
python inventory.py            # ваша работа
python check.py                # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию
python3 inventory.py           # ваша работа
python3 check.py               # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию
python3 inventory.py           # ваша работа
python3 check.py               # проверка, одна на все языки
PowerShellподготовка и запуск
# драйвер C++ под Windows собирается долго — всё делаем в контейнерах
docker compose run --rm reset
docker compose run --rm cpp kt01/inventory.cpp
docker compose run --rm python kt01/check.py   # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию

g++ -std=c++17 inventory.cpp -o inventory \
    $(pkg-config --cflags --libs libmongocxx1)   # brew install mongo-cxx-driver
./inventory                     # решение
python3 check.py               # проверка, одна на все языки
Терминалподготовка и запуск
# в пакетах дистрибутива драйвер C++ старый — всё делаем в контейнерах
docker compose run --rm reset
docker compose run --rm cpp kt01/inventory.cpp
docker compose run --rm python kt01/check.py   # проверка, одна на все языки
PowerShellподготовка и запуск
docker compose run --rm reset          # учёт на 21 позицию
# без Docker: bash ../stend/load.sh в Git Bash
go run inventory.go            # ваша работа
python check.py                # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию
go run inventory.go            # ваша работа
python3 check.py               # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию
go run inventory.go            # ваша работа
python3 check.py               # проверка, одна на все языки
PowerShellподготовка и запуск
docker compose run --rm reset          # учёт на 21 позицию
# без Docker: bash ../stend/load.sh в Git Bash
ruby inventory.rb              # ваша работа
python check.py                # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию
ruby inventory.rb              # ваша работа
python3 check.py               # проверка, одна на все языки
Терминалподготовка и запуск
bash ../stend/load.sh          # учёт на 21 позицию
ruby inventory.rb              # ваша работа
python3 check.py               # проверка, одна на все языки

Сервер или драйвер не ставится — те же шаги выполняются в контейнерах, команды одинаковые в PowerShell и bash. Как поднять стенд и что делать при ошибках — глава 1.1а.

Терминалчерез Docker, из корня репозитория
docker compose up -d                                   # один раз: сервер и базы курса
docker compose run --rm reset                          # учёт на 21 позицию
docker compose run --rm python kt01/inventory.py
docker compose run --rm python kt01/check.py
Терминалчерез Docker, из корня репозитория
docker compose up -d                                   # один раз: сервер и базы курса
docker compose run --rm reset                          # учёт на 21 позицию
docker compose run --rm cpp kt01/inventory.cpp
docker compose run --rm python kt01/check.py
Терминалчерез Docker, из корня репозитория
docker compose up -d                                   # один раз: сервер и базы курса
docker compose run --rm reset                          # учёт на 21 позицию
docker compose run --rm go kt01/inventory.go
docker compose run --rm python kt01/check.py
Терминалчерез Docker, из корня репозитория
docker compose up -d                                   # один раз: сервер и базы курса
docker compose run --rm reset                          # учёт на 21 позицию
docker compose run --rm ruby kt01/inventory.rb
docker compose run --rm python kt01/check.py

Эталонные базы shop, hh, logs, org в работе не участвуют и меняться не должны — это проверяется на приёмке.

Язык работы — любой из четырёх: проверка смотрит на состояние базы, а не на код. Драйверы и команды запуска те же, что в ПР-01.

§2Что сделать

  1. Загрузить пересчётИз stocktake.json в коллекцию sandbox.stocktake — одним запросом. Повторный запуск скрипта не должен двоить данные.
  2. Сверить учёт с фактомПо артикулу разделить позиции на три группы: сошлось, недостача, излишек. Для каждой — количество позиций и список артикулов.
  3. Привести учёт в соответствиеДля позиций с расхождением записать фактическое количество в qty_accounted и добавить last_stocktake с датой. Позиции, где всё сошлось, не трогать — и доказать это числом modified_count.
  4. Пометить пустые полкиПозициям с нулевым фактическим остатком проставить available: false. У позиций, где товар есть, этого поля быть не должно.
  5. Записать в журналКоллекция sandbox.stocktake_log, один документ на инвентаризацию: дата, число позиций, число расхождений, суммарная недостача в штуках. Повторный запуск в тот же день не создаёт вторую запись.
  6. Написать отчётinventory.md по бланку: числа, запросы, которыми они получены, и вывод для заведующего складом.

§3Требования

числаКаждое число в отчёте получено запросом, а не посчитано глазами. Рядом с числом — запрос.обязательно
песочницаИзменения идут только в sandbox. Эталонные базы после работы совпадают с исходными.обязательно
повторный запускСкрипт можно запустить дважды, и база придёт к тому же состоянию.обязательно
счётчик перед правкойПеред массовым обновлением и удалением — count_documents с тем же фильтром.обязательно

§4Бланк отчёта

Структура задана — она же используется на приёмке. Полностью бланк лежит в репозитории, здесь его костяк.

inventory.md

  • 1. Что сверяли — данные, источник, число позиций в учёте и в пересчёте, артикулы, которых нет в учёте.
  • 2. Результат сверки — таблица «сошлось / недостача / излишек»: позиции и артикулы. Суммарная недостача и излишек в штуках.
  • 3. Что изменено в базе — по каждой операции: найдено, изменено, сам запрос. Если найдено и изменено различаются — объяснить почему.
  • 4. Пустые полки — артикул, название, полка.
  • 5. Что я проверил, чтобы не ошибиться — своими словами.
  • 6. Вывод — два-три предложения для заведующего складом.

§4аГде писать работу и как сдать

Работа пишется и сдаётся из того же собственного репозитория, что ПР-01. Если его ещё нет — первые два шага ниже.

mongodb-practice/

kt01/задание и check.py — отсюда запускается проверка
stend/данные и загрузка
work/ваш репозиторий
work/kt01/скрипт, inventory.md, копия stocktake.json
  1. Заведите свой репозиторийНа GitHub: New repository, имя вроде mongodb-ivanov, без README. Один репозиторий на все работы модуля.
  2. Склонируйте его в папку workВнутри mongodb-practice: git clone https://github.com/<ваш-логин>/mongodb-ivanov.git work. Папка work исключена из репозитория практик — ваши файлы в него не попадут, а стенд и Docker видят их так же, как всё остальное.
  3. Подготовьте папку работыСоздайте work/kt01 и скопируйте в неё пересчёт и бланк: cp kt01/stocktake.json kt01/report_template.md work/kt01/Copy-Item kt01\stocktake.json, kt01\report_template.md work\kt01\.
  4. Напишите скрипт и отчётinventory.pyinventory.cppinventory.goinventory.rb и inventory.md по бланку. Каждое число в отчёте — с запросом, которым оно получено.
  5. Проверьте дваждыСброс, скрипт, kt01/check.py — затем скрипт ещё раз и снова проверка. Второй запуск не должен ничего сломать. Вывод последней проверки вставьте в отчёт.
  6. Отправьте и пришлите ссылкуИз папки work: git add kt01, git commit -m "КТ-01: инвентаризация склада", git push.
Терминалваша работа: из корня mongodb-practice
docker compose run --rm reset
docker compose run --rm python work/kt01/inventory.py
docker compose run --rm python kt01/check.py
docker compose run --rm python work/kt01/inventory.py      # второй запуск
docker compose run --rm python kt01/check.py
Терминалваша работа: из корня mongodb-practice
docker compose run --rm reset
docker compose run --rm cpp work/kt01/inventory.cpp
docker compose run --rm python kt01/check.py
docker compose run --rm cpp work/kt01/inventory.cpp      # второй запуск
docker compose run --rm python kt01/check.py
Терминалваша работа: из корня mongodb-practice
docker compose run --rm reset
docker compose run --rm go work/kt01/inventory.go
docker compose run --rm python kt01/check.py
docker compose run --rm go work/kt01/inventory.go      # второй запуск
docker compose run --rm python kt01/check.py
Терминалваша работа: из корня mongodb-practice
docker compose run --rm reset
docker compose run --rm ruby work/kt01/inventory.rb
docker compose run --rm python kt01/check.py
docker compose run --rm ruby work/kt01/inventory.rb      # второй запуск
docker compose run --rm python kt01/check.py

Так выглядит проверка до начала работы — ни один шаг ещё не сделан. Скрипт говорит, что не так, но не подсказывает ответы:

Вывод check.pyнетронутые данные
Шаг 1 · пересчёт загружен
 ✗ коллекция sandbox.stocktake заполнена
     документов в коллекции: 0, а в файле: 21
 ✓ повторная загрузка не задвоила данные

Шаг 3 · учёт приведён в соответствие
 ✗ учётные остатки совпали с фактом по всем позициям
     учёт ещё не совпадает с пересчётом: сверьте qty_accounted с полем counted по каждому артикулу
 ✗ отметка о дате инвентаризации проставлена
     поле last_stocktake должно появиться у позиций с расхождением
 ✓ позиции без расхождений не переписаны без нужды

Шаг 4 · пустые полки помечены
 ✗ помечены все позиции с нулевым фактом
     не у всех позиций с нулевым пересчётом стоит available: false
 ✓ лишние позиции не помечены

Шаг 5 · журнал инвентаризации
 ✗ в журнале ровно одна запись
     записей в sandbox.stocktake_log: 0; повторный запуск не должен добавлять вторую
 ✗ в записи журнала есть дата и числа
     ожидаются поля date, positions, mismatches

Эталонные базы
 ✓ shop.products не тронута
 ✓ shop.orders не тронута

Не сошлось: 6. Работа возвращается на доработку.
VS Code на macOS: запуск kt01/check.py до начала работы и его вывод
VS Code · macOS · check.py до начала работы — шесть пунктов не сошлось, ответы не подсказываются

§5Как принимается

База пересоздаётся из репозитория, запускается ваш скрипт, числа из отчёта сверяются с тем, что получилось. Расхождение любого числа — работа возвращается.

КритерийЧто смотрят
Числа сходятсяОтчёт против базы после запуска вашего скрипта
Скрипт повторяемВторой запуск не меняет результат и не плодит записи
Эталон не тронутshop, hh, logs, org совпадают с исходными
Отчёт читаетсяВывод понятен человеку, который не открывал базу
Вопросы на приёмке

Почему у вас modified_count меньше, чем найдено документов. Что произойдёт, если запустить скрипт дважды. Как вы убедились, что не изменили эталонные базы. Какой запрос вы бы написали, если бы позиций было не 21, а миллион. Последний вопрос — про то, что перебор в Python перестанет работать; отвечают на него уже средствами модуля 4.

§6Подсказки, которые не выдают решение

  • Сверка 21 позиции спокойно делается перебором в Python: сложите пересчёт в словарь {sku: counted} и пройдите по учёту.
  • $set записывает значение, $inc меняет на разницу. Здесь честнее $set: вы записываете факт, а не поправку.
  • «Не плодить записи за ту же дату» — это update_one(..., upsert=True) с датой в фильтре.
  • Дата берётся как datetime.now(timezone.utc), ключ журнала — строка вида 2026-09-09.
  • Поле, которого не должно быть, убирается через $unset, а не записью None.

После контрольной

Дальше — модуль 2: язык фильтров целиком. Там появятся сравнения, «или», условия по массивам и проверка существования поля, и та же инвентаризация уложится в один запрос вместо перебора.

Контрольная точка 01 · Справочник по MongoDB Автор: Макаров Максим Николаевич