3

Let's say we have a collection with documents as below

{_id:1, name:'a', category:'c1', count:1}
{_id:2, name:'b', category:'c1', count:3}
{_id:3, name:'c', category:'c1', count:5}
{_id:4, name:'d', category:'c2', count:2}
{_id:5, name:'e', category:'c2', count:3}
{_id:6, name:'f', category:'c2', count:6}
{_id:7, name:'g', category:'c2', count:7}

I'm trying to construct some sort of "aggregation" pipeline to

  1. Group documents by category
  2. For each category, return top 2 documents by count in descending order

So in this case, the expected result should be something like

[
    {_id:'c1: docs:[
        {_id:3, name:'c', category:'c1', count:5},
        {_id:2, name:'b', category:'c1', count:3}
    ]},
    {_id:'c2: docs:[
        {_id:7, name:'g', category:'c2', count:7},
        {_id:6, name:'f', category:'c2', count:6}
    ]},        
]

Currently, I take multiple steps to produce the result

  1. Identify category list
  2. Repeat find {category:x}, {sort:[['count', 'desc']], limit:2} command
  3. Merge results into one common array

Is there anyway to achieve this in "aggregation" manner?

Community
  • 1
  • 1
Lee
  • 2,874
  • 3
  • 27
  • 51

1 Answers1

0

Managed to figure out the answer myself. It's something as below.

collection.aggregate([
    {$sort:{category:1, count:-1}},
    {$group:{_id:'$category', docs:{$push:{_id:'$_id', name:'$name', count:'$count'}}}},
    {$project:{_id:1, docs:{$slice:['$docs', 2]}}}
])

$sort, $push and $slice work tegether to play the tricks.

Lee
  • 2,874
  • 3
  • 27
  • 51