Как выполнить $match и $sort перед $group

Вопрос или проблема

У меня есть функция агрегации mongo, которая подсчитывает количество документов по группировке некоторых полей. И на самом деле мне нужно только число в качестве идентификатора и поле с количеством, как у меня уже есть.

Но также мне нужно выполнить $sort и $match в моей функции агрегации, но из-за того, что у моего документа всего 2 поля после группировки, я предполагаю, что $sort и $match не работают.

Как я могу сначала выполнить sort и match, а затем сделать group by?

Моя функция агрегации:

db.collection.aggregate([
  {
    "$sort": {
      "updated_at": -1
    }
  },
  {
    "$match": {
      "user": "aboba"
    }
  },
  {
    "$group": {
      "_id": {
        "number": "$number",
        "user": "$user"
      }
    }
  },
  {
    "$group": {
      "_id": "$_id.user",
      "count": {
        "$sum": 1
      }
    }
  },
  {
    "$unwind": "$_id"
  }
])

Mongo Playground

В моей функции агрегации я точно могу сказать, что сортировка по обновленной дате совсем не работает.

Ответ или решение

Чтобы правильно использовать операции $match и $sort перед группировкой ($group) в MongoDB, необходимо учесть порядок выполнения стадий агрегации. Операции агрегации выполняются последовательно, и Каждый последующий этап работает с результатами предыдущего. Важно помнить, что после применения $group мы не можем использовать первичные поля документа, которые были сгруппированы, в стадии $sort или $match, потому что на этом этапе этих полей больше нет.

Давайте разберемся, как правильно перестроить ваш запрос, чтобы операции $sort и $match работали должным образом до группировки.

  1. Сначала используем $match, чтобы отфильтровать документы. Это позволяет сократить объем данных, которые будут обработаны на следующих этапах, и тем самым улучшить производительность агрегации.

  2. Затем применяем $sort, чтобы отсортировать отфильтрованные документы.

  3. После этого можем использовать $group, чтобы подсчитать количество документов по нужным полям.

Вот как должен выглядеть ваш агрегационный запрос:

db.collection.aggregate([
  {
    "$match": {
      "user": "aboba"
    }
  },
  {
    "$sort": {
      "updated_at": -1
    }
  },
  {
    "$group": {
      "_id": {
        "number": "$number",
        "user": "$user"
      }
    }
  },
  {
    "$group": {
      "_id": "$_id.user",
      "count": {
        "$sum": 1
      }
    }
  },
  {
    "$unwind": "$_id"
  }
])

Объяснение:

  1. "$match" сначала отфильтрует все документы, оставив лишь те, у которых поле user равно "aboba". Это уменьшает количество документов, которые будут обрабатываться на следующих этапах.

  2. "$sort" выполнит сортировку оставшихся документов по полю updated_at в порядке убывания.

  3. Затем с помощью "$group" вы сгруппируете документы по полям number и user.

  4. После этого еще один $group подсчитает количество документов для каждого уникального пользователя.

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

Используя данный порядок стадий, вы сможете успешно выполнить операции $match, $sort и $group, как требуется.

Оцените материал
Добавить комментарий

Капча загружается...