За пределами основ: продвинутые команды MongoDB для анализа данных

Используйте продвинутые фильтры MongoDB, проекции и этапы агрегации для анализа данных без их выгрузки из базы данных.

За пределами основ: продвинутые команды MongoDB для анализа данных

Запросы MongoDB становятся более полезными, когда вы выходите за рамки простых вызовов find(). Если вам нужно фильтровать вложенные документы, изменять форму вывода или вычислять сгруппированные результаты, продвинутые операторы запросов и этапы агрегации позволяют выполнять эту работу непосредственно с данными.

Примеры ниже сосредоточены на практических командах, которые можно выполнять в mongosh для составления отчетов, устранения неполадок и разового анализа.

Освоение сложной фильтрации с помощью операторов запросов

В то время как базовый метод find() обрабатывает простые проверки на равенство, продвинутый анализ часто требует комбинирования нескольких условий или запроса определенных структур полей. MongoDB предоставляет богатый набор операторов запросов для создания детализированных фильтров.

Логические операторы для составных запросов

Логические операторы позволяют комбинировать несколько условий запроса, обеспечивая точный контроль над возвращаемыми документами. Они необходимы для структурирования сложных аналитических вопросов.

  • $and / Неявный $and: Используется для указания нескольких критериев, которые все должны быть истинными. Хотя часто неявный (перечисление условий последовательно в объекте запроса), $and необходим при запросе одного и того же поля несколько раз.
    // Неявный $and: Найти пользователей старше 25 И живущих в Нью-Йорке
    db.users.find({ age: { $gt: 25 }, city: "New York" });
    
    // Явный $and: Найти документы, где 'score' > 90 ИЛИ 'level' равен 5
    db.results.find({ $and: [ { score: { $gt: 90 } }, { level: 5 } ] });
    
  • $or: Выбирает документы, соответствующие любому из указанного массива выражений.
    db.products.find({ $or: [ { category: "Electronics" }, { price: { $lt: 100 } } ] });
    
  • $not: Отрицает результаты указанного выражения.

Геопространственные операторы и операторы для массивов

Для данных, основанных на местоположении, или сложных массивов специализированные операторы предоставляют аналитическую мощность:

  • $geoWithin / $near: Необходимы для поиска данных в определенной географической области или поблизости.
  • $elemMatch: Критически важен для запросов к массивам встроенных документов, гарантируя, что один элемент в массиве соответствует всем указанным критериям внутри $elemMatch.
    // Найти заказы, где хотя бы один товар в массиве 'items' стоит более 500 И имеет количество больше 1
    db.orders.find({ items: { $elemMatch: { price: { $gt: 500 }, qty: { $gt: 1 } } } });
    

Продвинутая проекция: формирование вывода

Проекция, управляемая с помощью второго аргумента в методе find(), определяет, какие поля возвращаются. Продвинутая проекция выходит за рамки простого включения/исключения для преобразования или формирования возвращаемых данных.

Исключение и включение полей

  • 1 включает поле; 0 исключает поле.
  • Важное примечание: Нельзя смешивать включение (1) и исключение (0), за исключением поля _id (которое включено по умолчанию и может быть явно исключено установкой в 0).
// Включить только 'name' и 'email', исключить '_id'
db.users.find({}, { name: 1, email: 1, _id: 0 });

Нарезка и манипуляция массивами

Проекция может ограничить количество возвращаемых элементов массива с помощью $slice:

  • $slice: N: Возвращает первые N элементов.
  • $slice: -N: Возвращает последние N элементов.
  • $slice: [M, N]: Возвращает N элементов, начиная с индекса M.
// Вернуть только последние 3 записи из массива 'history'
db.logs.find({}, { history: { $slice: -3 } });

Анализ данных с помощью Aggregation Framework

MongoDB Aggregation Framework — это самый мощный инструмент для сложного анализа данных, позволяющий обрабатывать записи данных через конвейер этапов. Каждый этап выполняет определенное преобразование или операцию над данными, переданными с предыдущего этапа.

Ключевые этапы агрегации

Базовая структура использует db.collection.aggregate([...pipeline]).

1. $match (Фильтрация)

Функционирует аналогично find(), но применяется до последующих этапов, оптимизируя производительность за счет раннего уменьшения набора данных.

2. $group (Группировка и вычисление)

Этот этап группирует документы по указанному идентификатору (_id) и применяет операторы-аккумуляторы для вычисления сводной статистики.

Распространенные аккумуляторы:

  • $sum
  • $avg
  • $min, $max
  • $push (для сбора данных массива из группы)
// Вычислить средний балл по каждому отделу
db.scores.aggregate([
  { $group: { 
    _id: "$department", 
    averageScore: { $avg: "$score" },
    totalStudents: { $sum: 1 }
  } }
]);

3. $project (Изменение формы документов)

Используется в агрегации для изменения формы выходных документов, аналогично проекции в find(), но часто используется для создания новых вычисляемых полей.

  • Вычисляемые поля: Вы можете выполнять вычисления внутри этапа проекции, используя существующие поля.
// Вычислить маржу прибыли в конвейере
db.sales.aggregate([
  { $project: { 
    _id: 0, 
    productName: 1,
    profit: { $subtract: ["$salePrice", "$cost"] }
  } }
]);

4. $lookup (Объединение данных)

Этап $lookup добавляет соответствующие документы из другой коллекции, аналогично левому внешнему соединению. Он полезен, когда нужно обогатить документы для отчетности без выполнения объединения в коде приложения.

// Объединение коллекции 'orders' с коллекцией 'customers'
db.orders.aggregate([
  { $match: { status: "Pending" } },
  { $lookup: {
      from: "customers",         // Коллекция для объединения
      localField: "customerId",  // Поле из входных документов (orders)
      foreignField: "_id",       // Поле из документов коллекции "from" (customers)
      as: "customerDetails"      // Имя выходного поля массива
  } }
]);

5. $unwind (Деконструкция массивов)

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

Предупреждение: $unwind может значительно увеличить количество документов. Используйте его разумно, обычно после $match, чтобы уменьшить исходный набор.

Лучшие практики для аналитических запросов

  1. Индексируйте точки входа: Индексируйте поля, используемые на ранних этапах $match, и этапы $sort, поддерживаемые индексами. $group может выиграть от меньшего количества входных документов, но он не становится автоматически быстрым только потому, что у группируемого поля есть индекс.
  2. Фильтруйте рано: Размещайте этапы $match как можно раньше в конвейере агрегации. Раннее уменьшение количества документов значительно экономит вычислительную мощность для последующих, более дорогих этапов, таких как $lookup или $group.
  3. Используйте соответствующие типы данных: Убедитесь, что поля сравнения (например, даты или числовые значения) хранятся согласованно. Несоответствие типов приводит к тому, что операторы $match работают неэффективно или незаметно.

Используйте эти команды, когда простого извлечения данных недостаточно. Начните с избирательных фильтров, проектируйте только нужные поля и переходите к агрегации, когда вам нужна группировка, изменение формы или обогащение данных из коллекции в коллекцию.