Подтвердить что ты не робот

Получение результата $group с количеством групп

Предполагая, что у меня есть коллекция под названием "posts" (на самом деле это более сложная коллекция, сообщения слишком просты) со следующей структурой:

> db.posts.find()

{ "id" : ObjectId("50ad8d451d41c8fc58000003"), "title" : "Lorem ipsum", "author" : 
"John Doe", "content" : "This is the content", "tags" : [ "SOME", "RANDOM", "TAGS" ] }

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

db.posts.aggregate(
  { "unwind" : "$tags" },
  { "group" : {
      _id: { tag: "$tags" },
      count: { $sum: 1 }
  } }
);

Ловушка заключается в том, что для создания paginator мне понадобится знать длину выходного массива. Я знаю, что вы можете сделать это:

db.posts.aggregate(
  { "unwind" : "$tags" },
  { "group" : {
      _id: { tag: "$tags" },
      count: { $sum: 1 }
  } }
  { "group" : {
      _id: null,
      total: { $sum: 1 }
  } }
);

Но это отбрасывает вывод из предыдущего конвейера (первая группа). Есть ли способ объединить две операции при сохранении каждого выходного конвейера? Я знаю, что вывод всей операции агрегата может быть передан в массив на каком-то языке и подсчитывается содержимое, но может быть вероятность того, что выход конвейера может превысить предел 16 Мб. Кроме того, выполнение одного и того же запроса только для получения счета кажется ненужным.

Итак, получается результат документа и рассчитывается одновременно? Любая помощь приветствуется.

4b9b3361

Ответ 1

  • Используйте $project для сохранения tag и count в tmp
  • Используйте $push или addToSet для хранения tmp в списке data.

код:

db.test.aggregate(
    {$unwind: '$tags'}, 
    {$group:{_id: '$tags', count:{$sum:1}}},
    {$project:{tmp:{tag:'$_id', count:'$count'}}}, 
    {$group:{_id:null, total:{$sum:1}, data:{$addToSet:'$tmp'}}}
)

Вывод:

{
    "result" : [
            {
                    "_id" : null,
                    "total" : 5,
                    "data" : [
                            {
                                    "tag" : "SOME",
                                    "count" : 1
                            },
                            {
                                    "tag" : "RANDOM",
                                    "count" : 2
                            },
                            {
                                    "tag" : "TAGS1",
                                    "count" : 1
                            },
                            {
                                    "tag" : "TAGS",
                                    "count" : 1
                            },
                            {
                                    "tag" : "SOME1",
                                    "count" : 1
                            }
                      ]
              }
      ],
      "ok" : 1
}

Ответ 2

Я не уверен, что вам нужна структура агрегации для этого, кроме подсчета всех тегов, например:

db.posts.aggregate(
  { "unwind" : "$tags" },
  { "group" : {
      _id: { tag: "$tags" },
      count: { $sum: 1 }
  } }
);

Для разбиения на страницы по тегу вы можете просто использовать обычный синтаксис запроса - например:

db.posts.find({tags: "RANDOM"}).skip(10).limit(10)