1

I want to query documents and return a list of objects representing all categories, with an array of objects within each category object, containing the documents matching that category.

If it helps to explain: the database has a list of documents representing news articles, and I need to display them grouped by category on the front end, so I'll need an object for each category, with each category object containing an array of the articles (as objects) to display under that category.

I have documents of the following form:

{ 
    "date" : ISODate("2018-06-25T00:00:00.000+0000"), 
    "detail" : {
        "category" : "world", 
        "title" : "stuff is happening", 
        "content" : "lorem ipsum dolor"
    } 
}
{ 
    "date" : ISODate("2018-03-08T00:00:00.000+0000"), 
    "detail" : {
        "category" : "national", 
        "title" : "more stuff is happening", 
        "content" : "sit amet"
    } 
}
{ 
    "date" : ISODate("2018-02-02T00:00:00.000+0000"), 
    "detail" : {
        "category" : "local", 
        "title" : "local stuff is happening", 
        "content" : "not much happening locally"
    }
}

...and I would like my result to look something like this:

{  _id: "world",
   count: 3,
   "articles" : {[
       {
       "date" : ISODate("2018-06-25T00:00:00.000+0000"), 
       "detail" : {
           "category" : "world", 
           "title" : "stuff is happening", 
           "content" : "lorem ipsum dolor"
       },
       {
       "date" : ISODate("2018-06-25T00:00:00.000+0000"), 
       "detail" : {
           "category" : "world", 
           "title" : "stuff is happening #2", 
           "content" : "lorem ipsum dolor"
       },
       {
       "date" : ISODate("2018-06-25T00:00:00.000+0000"), 
       "detail" : {
           "category" : "world", 
           "title" : "stuff is happening #3", 
           "content" : "lorem ipsum dolor"
       }
    ]}
}
{ _id: "national",
   count: 1,
   "articles" : {[
     {
       "date" : ISODate("2018-03-08T00:00:00.000+0000"), 
       "detail" : {
           "category" : "national", 
           "title" : "more stuff is happening", 
           "content" : "sit amet"
       } 
     }
}

...and so on. So far, I have this query:

db.news_feed.aggregate([
{ $match: {} },
{ $group: {_id:'$detail.category', count: { $sum:1 } } },
{ $addFields: {
                    "article": "$$ROOT"
                }
} 
])

This gets me a summarized count of each category, but obviously the $$ROOT inserts the result after $group, not the original document(s):

{ 
    "_id" : "world", 
    "count" : 3.0, 
    "articles" : {
        "_id" : "world", 
        "count" : 3.0
    }
}
{ 
    "_id" : "national", 
    "count" : 1.0, 
    "brief" : {
        "_id" : "national", 
        "count" : 1.0
    }
}
{ 
    "_id" : "local", 
    "count" : 5.0, 
    "brief" : {
        "_id" : "local", 
        "count" : 5.0
    }
}
.
.

What can I do to insert an array of "articles" that are the original articles which are being summed up?

1 Answer 1

1

You need to use $push accumulator with the $group stage

db.news_feed.aggregate([
  { "$group": {
    "_id": "$detail.category",
    "articles": { "$push": "$$ROOT" },
    "count": { "$sum": 1 }
  }}
])
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much! The $push accumulator was exactly what I needed, but I didn't even know it existed. Today I learned.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.