charnould
charnould

Reputation: 2907

Aggregate using $group twice

I've read SO and questions like this one. However I'm not able to build the query I want...

Let's say I have the following data structure:

{ 
    "CAUG" : "id1", 
    "action" : "actionA", 
    "date" : ISODate("2017-01-01"), 
    "hp" : 16
}
{ 
    "CAUG" : "id1", 
    "action" : "actionB", 
    "date" : ISODate("2017-01-01"), 
    "hp" : 17
}
{ 
    "CAUG" : "id1", 
    "action" : "actionC", 
    "date" : ISODate("2017-02-10"), 
    "hp" : 18
}
{ 
    "CAUG" : "id2", 
    "action" : "actionX", 
    "date" : ISODate("2018-01-01"), 
    "hp" : 20
}...

The desired output is something like (not sure about brackets and other stuff...):

{ 
    "CAUG" : "id1", 
    "timeline" : [
        ISODate ("2017-01-01) {
            { "action" : "ActionA", hp : "..." }
            { "action" : "ActionB", hp : "..." }
        },
        ISODate ("2017-02-10) {
            { "action" : "ActionC", hp : "..." }
        }
    ]
}
{ 
    "CAUG" : "id2", 
    "timeline" : [
        ISODate ("2018-01-01) {
            { "action" : "ActionX", hp : "..." }
        }
    ]
}

At this time my (very limited) query is:

(I've tried many things like composite _id, but I'm alway stucked at some point).

db.aggregate(
    [
        { $match: { something } },
        { $project: { something } },
        { $group: {
              _id: '$CAUG',
              "timeline": { "$push": "$$ROOT"  }
            }
        }
    ]
)

The problem is I do not know how to do another $group inside timeline array... I'm stucked with the output below... Any clue please? Have a nice weekend.

{ 
    "_id" : "1", 
    "timeline" : [
        {
            "CAUG" : "ca220491-ug43816", 
            "action" : "actionA", 
            "date" : ISODate("2016-12-21T23:00:00.000+0000")
        }, 
        {
            "CAUG" : "ca220491-ug43816", 
            "action" : "actionB", 
            "date" : ISODate("2016-12-21T23:00:00.000+0000")
        }, 
        {
            "CAUG" : "ca220491-ug43816", 
            "action" : "actionC", 
            "date" : ISODate("2017-02-21T23:00:00.000+0000")
        }
    ]
}

Upvotes: 2

Views: 535

Answers (1)

chridam
chridam

Reputation: 103345

Try running the following aggregate operation:

db.collection.aggregate([
    {
        "$group": {
            "_id": {
                "CAUG": "$CAUG",
                "date": {
                    "$dateToString": {
                        "format": "%Y-%m-%d", 
                        "date": "$date"
                    }
                }
            },
            "docs": {
                "$push": {
                    "action" : "$action",
                    "hp" : "$hp"
                }
            }                
        }
    },
    {
        "$group": {
            "_id": "$_id.CAUG",
            "timeline": {
                "$push": {
                    "date": "$_id.date",
                    "docs": "$docs"
                }
            }
        }
    }
])

which gives the sample output

/* 1 */
{
    "_id" : "id1",
    "timeline" : [ 
        {
            "date" : "2017-02-10",
            "docs" : [ 
                {
                    "action" : "actionC",
                    "hp" : 18.0
                }
            ]
        }, 
        {
            "date" : "2017-01-01",
            "docs" : [ 
                {
                    "action" : "actionA",
                    "hp" : 16.0
                }, 
                {
                    "action" : "actionB",
                    "hp" : 17.0
                }
            ]
        }
    ]
}

/* 2 */
{
    "_id" : "id2",
    "timeline" : [ 
        {
            "date" : "2018-01-01",
            "docs" : [ 
                {
                    "action" : "actionX",
                    "hp" : 20.0
                }
            ]
        }
    ]
}

Upvotes: 2

Related Questions