Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB - group composite key with nested fields

Tags:

mongodb

I have this document in mongodb:

{
"_id":"26/04/2015 09:50",
"reservations":130,
"Event_types":[
   {
     "type":"Party",
     "events":[
        {
           "eventName":"After Party",
           "total_count":130,
           "by":[
              {
                 "siteName":"club8",
                 "countArray":[
                    {
                       "bucket":"default",
                       "value":40
                    }
                 ]
              },
              {
                 "siteName":"PostParty",
                 "countArray":[
                    {
                       "bucket":"1",
                       "value":70
                    },
                    {
                       "bucket":"2",
                       "value":20
                    }
                 ]
              }
           ]
        }
      ]
   }
 ]
}

What I'm looking for

I wish to sum the "value" field and group by these fields:

  1. type
  2. eventName
  3. siteName

So for the document I have I would expect to get:

  1. For the combination {"Party","After Party","club8"} a sum of 40
  2. For the combination {"Party","After Party","PostParty"} a sum of 90

What I've tried

I've tried using the aggregate operator with a composite key for the _id:

db.testing.aggregate(
{ 
$group : {
    _id : 
    {
    type:'$Event_types.type',
    name: '$Event_types.events.eventName',
    siteName: '$Event_types.events.by.siteName'
    }
    , total : { $sum : '$Event_types.events.by.countArray.value' }
}
});

The results

one document, with 3 arrays - one for every value I wish to group by. The "siteName" array contains the 2 values available for "siteName". The "total" doesn't seem to sum up anything, and it appears only once - I expected to see it next to each "SiteName" value in the document.

 {
   "_id":{
      "type":[
         "Party"
      ],
      "name":[
         [
            "After Party"
         ]
      ],
      "siteName":[
         [
            [
               "club8",
               "PostParty"
            ]
         ]
      ]
   },
   "total":0
}

Am I using "aggregate" the wrong way or is the schema I'm using not fit for my goal? Thank you.

like image 946
assafm Avatar asked Apr 26 '15 15:04

assafm


People also ask

How do I display multiple fields in MongoDB?

In MongoDB, When you want to perform any operation on multiple fields then you have to use $group aggregation. You will more understand with help of examples. Example: In the example, I will show you how you can display some particular documents with multiple fields when we have a large dataset in the collection.

What is $project in MongoDB?

Definition. $project. Passes along the documents with the requested fields to the next stage in the pipeline. The specified fields can be existing fields from the input documents or newly computed fields.


1 Answers

You need to first apply the $unwind operator on all the arrays so that you can do the aggregation calculations with the $group operator later in the pipeline stages. In the end you will end up with an aggregation pipeline like this:

db.testing.aggregate([
    { "$unwind": "$Event_types" },
    { "$unwind": "$Event_types.events" },
    { "$unwind": "$Event_types.events.by" },
    { "$unwind": "$Event_types.events.by.countArray" },
    {
        "$group": {
            "_id": {
                "type": "$Event_types.type",
                "name": "$Event_types.events.eventName",
                "siteName": "$Event_types.events.by.siteName"
            },
            "total": { 
                "$sum": "$Event_types.events.by.countArray.value"
            }
        }
    },
    {
        "$project": {
            "_id": 0,
            "type": "$_id.type",
            "name": "$_id.name",
            "siteName": "$_id.siteName",
            "total": 1
        }
    }
]);

Output

/* 1 */
{
    "result" : [ 
        {
            "total" : 90,
            "type" : "Party",
            "name" : "After Party",
            "siteName" : "PostParty"
        }, 
        {
            "total" : 40,
            "type" : "Party",
            "name" : "After Party",
            "siteName" : "club8"
        }
    ],
    "ok" : 1
}
like image 85
chridam Avatar answered Oct 15 '22 12:10

chridam