2

I am using mongodb aggregation for getting counts of different fields. Here are some documents from the mobile collection:-

{
  "title": "Moto G",
  "manufacturer": "Motorola",
  "releasing": ISODate("2011-03-00T10:26:48.424Z"),
  "rating": "high"
}
{
  "title": "Asus Zenfone 2",
  "manufacturer": "Asus",
  "releasing": ISODate("2014-10-00T10:26:48.424Z"),
  "rating": "high"
}
{
  "title": "Moto Z",
  "manufacturer": "Motorola",
  "releasing": ISODate("2016-10-12T10:26:48.424Z"),
  "rating": "none"
}
{
  "title": "Asus Zenfone 3",
  "manufacturer": "Asus",
  "releasing": ISODate("2016-08-00T10:26:48.424Z"),
  "rating": "medium"
}

I can find manufacturer and rating counts but this fails:

db.mobile.aggregate([
    {
        $group: { _id: "$manufacturer", count: { $sum: 1 } }
    }, {
        $group: { _id: "$rating", count: { $sum: 1 } }
    }
])

Output:-

{
    "_id" : null,
    "count" : 2.0
}

Expected Output something like:-

  {
      "_id":"Motorola",
      "count" : 2.0
  }
  {
      "_id":"Asus",
      "count" : 2.0
  } 
  {
      "_id":"high",
      "count" : 2.0
  }
  {
      "_id":"none",
      "count" : 1.0
  }
  {
      "_id":"medium",
      "count" : 1.0
  }
chridam
  • 100,957
  • 23
  • 236
  • 235
vineet
  • 13,832
  • 10
  • 56
  • 76

1 Answers1

4

I believe you are after an aggregation operation that groups the documents by the manufacturer and rating keys, then do a further group on the manufacturer while aggregating the ratings per manufacturer, something like the following pipeline:

db.mobile.aggregate([
    {
        "$group": {
            "_id": { 
                "manufacturer": "$manufacturer",
                "rating": "$rating"
            },
            "count": { "$sum": 1 }
        }
    },
    { 
        "$group": {
            "_id": "$_id.manufacturer",
            "total": { "$sum": 1 },
            "counts": {
                "$push": {
                    "rating": "$_id.rating",
                    "count": "$count"
                }
            }
        }
    }
])

Sample Output

/* 1 */
{
    "_id" : "Motorola",
    "total" : 2,
    "counts" : [ 
        {
            "rating" : "high",
            "count" : 1
        }, 
        {
            "rating" : "none",
            "count" : 1
        }
    ]
}

/* 2 */
{
    "_id" : "Asus",
    "total" : 2,
    "counts" : [ 
        {
            "rating" : "high",
            "count" : 1
        }, 
        {
            "rating" : "medium",
            "count" : 1
        }
    ]
}

or if you are after a more "flat" or "denormalised" result, run this aggregate operation:

db.mobile.aggregate([
    { 
        "$group": { 
            "_id": "$manufacturer",  
            "total": { "$sum": 1 },           
            "high_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", "high" ] }, 1, 0 ]
                }
            },
            "medium_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", "medium" ] }, 1, 0 ]
                }
            },
            "low_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", "low" ] }, 1, 0 ]
                }
            },            
            "none_ratings": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$rating", "none" ] }, 1, 0 ]
                }
            }           
        }  
    }
])

Sample Output

/* 1 */
{
    "_id" : "Motorola",
    "total" : 2,
    "high_ratings" : 1,
    "medium_ratings" : 0,
    "low_ratings" : 0,
    "none_ratings" : 1
}

/* 2 */
{
    "_id" : "Asus",
    "total" : 2,
    "high_ratings" : 1,
    "medium_ratings" : 1,
    "low_ratings" : 0,
    "none_ratings" : 0
}
chridam
  • 100,957
  • 23
  • 236
  • 235