Две парадигмы запросов к документным данным
В экосистемах CouchDB и MongoDB исторически сосуществуют низкоуровневые map/reduce views (CouchDB) и aggregation map-reduce stages (MongoDB legacy), а также декларативные JSON-запросы — Mango Query в CouchDB и find()/aggregation $match в MongoDB. Выбор подхода влияет на latency, стоимость индексного обслуживания, сложность разработки и поведение при росте объёма данных.
Оптимизация запросов начинается не с «переписать на другой API», а с профиля access: point read по _id, range scan по полю, full-text, ad-hoc analytics, materialized counter. Ниже — когда MapReduce оправдан, когда Mango (или MongoDB indexes + aggregation) выигрывает, и как комбинировать подходы без дублирования логики.
MapReduce: как работает и где силён
Классический MapReduce в CouchDB — JavaScript (или Erlang) map function emit(key, value) для каждого документа и reduce для агрегации по ключам. View инкрементально обновляется при изменении документов и материализуется в B-tree — запрос к view быстр после построения индекса.
В MongoDB mapReduce command (устаревающий) выполнял map/reduce functions over collection с output в коллекцию или inline — сегодня официально рекомендуют aggregation pipeline и $function только где необходимо.
Сильные стороны
- Сложная логика извлечения ключа в map — nested arrays, conditional emit.
- Materialized aggregates (count, sum) через built-in reducers (_count, _sum, _stats).
- Один раз построили view — многократные read без re-scan всей коллекции (CouchDB).
Слабые стороны
- Cold build view на большой базе блокирует и потребляет CPU/IO.
- JavaScript map в CouchDB медленнее native Mango index path.
- Сложность отладки: ошибка в map ломает index update для документа.
- MongoDB mapReduce не использует indexes так же эффективно, как aggregation + $match first.
Mango Query: декларативный доступ в CouchDB
Mango (Cloudant Query / CouchDB 2+) — JSON selector с операторами $eq, $gt, $in, $regex, compound $and/$or. Индексы задаются явно через _index с полями sort и filter. Запрос planner выбирает подходящий index или fallback на full scan (с warning в logs).
Преимущества Mango
- Близко к ментальной модели SQL WHERE / Mongo find;
- Partial indexes для subset документов (type = "order" AND status);
- Быстрее time-to-market для CRUD-списков и фильтров админки;
- Меньше custom code в map functions — проще code review.
Ограничения
- Глубокая агрегация across documents — не замена reduce; нужен отдельный view, aggregation job или external analytics DB.
- $regex без anchor и без index-friendly prefix — COLLSCAN equivalent.
- Сложные условия на nested arrays требуют аккуратного index design или denormalization.
Сравнение в контексте MongoDB
Аналог Mango в MongoDB — find() + compound indexes и aggregation pipeline. «MapReduce»-style задачи решают через:
- $match + $group + $project — preferred для analytics in-database;
- $lookup — join между коллекциями с cost awareness;
- materialized views pattern — nightly job пишет aggregates в stats collection;
- Change Streams + consumer — incremental counters без full re-reduce.
MongoDB mapReduce command оставлен для legacy; новые проекты не должны на него опираться. Performance Advisor подсказывает missing indexes для find/agg — аналог мониторинга Mango _explain.
Практические правила выбора
Используйте следующую эвристику:
- Point get by _id — всегда primary key, без view и без Mango если не нужен secondary sort.
- Список с фильтром по 1–3 полям и sort — Mango / Mongo index + find или $match first stage.
- Глобальный counter или leaderboard — CouchDB view с _sum/_count или Mongo incremental update + atomic $inc.
- Ad-hoc report раз в сутки — ETL в warehouse, не on-line mapReduce на prod.
- Full-text — CouchDB search index / MongoDB Atlas Search, не regex on huge field.
Оптимизация Mango-запросов
- Создайте index на все поля в selector и sort в consistent order;
- Используйте _explain (CouchDB) или executionStats (Mongo) — rejected plans;
- Избегайте $or без union index strategy — иногда два запроса и merge in app дешевле;
- Limit + bookmark pagination вместо large skip;
- Denormalize hot filter fields при write, если index explosion на arrays.
Оптимизация MapReduce views
- Emit только минимальный key/value — fat values раздувают index;
- Используйте built-in reducers вместо custom JS reduce;
- partition views по type prefix если база multi-tenant;
- Мониторьте index lag после bulk import — staged import + pause queries until caught up;
- Для Mongo legacy mapReduce — миграция pipeline с $match indexed first.
Гибридная архитектура
Production системы часто комбинируют: Mango (или Mongo find) для online API, фоновый view или aggregation job для dashboard metrics, Elasticsearch для search. Дублировать одну и ту же бизнес-логику в map и Mango — источник drift; выделите single source of truth для derived fields при write (trigger, change stream handler).
Пример: интернет-магазин на CouchDB — Mango index на {status, createdAt} для списка заказов в админке; view orders_by_day emit [date, status], 1 для отчёта; nightly compact и monitor view build time. При росте отчётности — replicate subset в analytics DB, не расширять reduce online.
Антипatterns
- Map function с emit на каждый document без selective filter — view size ≈ N × fields.
- Mango query без index в prod на million docs — timeout under load.
- Regex ^.*keyword для search — full scan; dedicated search engine.
- Reduce re-run full collection hourly вместо incremental maintenance.
- Один giant aggregation pipeline без $match first — 100GB docs scanned per request.
Когда нужна внешняя помощь
Если profiler показывает repeated slow queries, index size растёт быстрее данных, или migration с mapReduce views на Mango stalled — имеет смысл audit access patterns и index catalog. Часто 2–3 правильных compound index снимают 80% latency без смены СУБД.
Разбор ваших запросов, views и плана индексов — на консультации по оптимизации MapReduce и Mango Query.
Как выбирать между MapReduce и Mango
Mango (declarative find) удобен для типовых фильтров и сортировок, когда есть подходящий индекс. MapReduce и view — когда нужна кастомная агрегация и материализованная перспектива данных. В MongoDB-мире аналогичная вилка: find и aggregation pipeline против устаревшего mapReduce command (его лучше не тащить в новый код).
Ошибка — гонять тяжёлый full scan через удобный API «потому что читается проще». Сначала explain и индекс, потом синтаксический сахар. Для отчётов с редким пересчётом иногда выгоднее precompute в отдельную коллекцию по расписанию.
- OLTP-запросы — индексы и простой find/Mango
- Сложные агрегаты — pipeline или view с понятным refresh
- Избегать mapReduce в новых MongoDB-сервисах




