数组内的多个嵌套组

5a0*_*01P 5 mongodb mongodb-query aggregation-framework

我在 MongoDB 中有一组元素,如下所示:

/* 1 */
{
    "_id" : ObjectId("58736c7f7d43c305461cdb9b"),
    "Name" : "Kevin",
    "pb_event" : [ 
        {
            "event_type" : "Birthday",
            "event_date" : "2014-08-31"
        }, 
        {
            "event_type" : "Anniversary",
            "event_date" : "2014-08-31"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("58736cfc7d43c305461cdba8"),
    "Name" : "Peter",
    "pb_event" : [ 
        {
            "event_type" : "Birthday",
            "event_date" : "2014-08-31"
        }, 
        {
            "event_type" : "Anniversary",
            "event_date" : "2015-03-24"
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("58736cfc7d43c305461cdba9"),
    "Name" : "Pole",
    "pb_event" : [ 
        {
            "event_type" : "Birthday",
            "event_date" : "2015-03-24"
        }, 
        {
            "event_type" : "Work Anniversary",
            "event_date" : "2015-03-24"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

现在我想要的结果是 group on event_datethen after group on event_typeevent_type包含相关用户的所有名称,然后是相应数组中的记录数。

预期输出

/* 1 */
{    
    "event_date" : "2014-08-31",
    "data" : [ 
        {
            "event_type" : "Birthday",
            "details" : [ 
                {
                    "_id" : ObjectId("58736c7f7d43c305461cdb9b"),
                    "name" : "Kevin"
                }, 
                {
                    "_id" : ObjectId("58736cfc7d43c305461cdba8"),
                    "name" : "Peter"
                }
            ],
            "count" : 2
        }, 
        {
            "event_type" : "Anniversary",
            "details" : [ 
                {
                    "_id" : ObjectId("58736c7f7d43c305461cdb9b"),
                    "name" : "Kevin"
                }
            ],
            "count" : 1
        }
    ]
}

/* 2 */
{
    "event_date" : "2015-03-24",
    "data" : [ 
        {
            "event_type" : "Anniversary",
            "details" : [ 
                {
                    "_id" : ObjectId("58736cfc7d43c305461cdba8"),
                    "name" : "Peter"
                }
            ],
            "count" : 1
        }, 
        {
            "event_type" : "Birthday",
            "details" : [ 
                {
                    "_id" : ObjectId("58736cfc7d43c305461cdba9"),
                    "name" : "Pole"
                }
            ],
            "count" : 1
        }, 
        {
            "event_type" : "Work Anniversary",
            "details" : [ 
                {
                    "_id" : ObjectId("58736cfc7d43c305461cdba9"),
                    "name" : "Pole"
                }
            ],
            "count" : 1
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

chr*_*dam 4

使用聚合框架,您需要运行具有以下阶段的管道,以便获得所需的结果:

db.collection.aggregate([
    { "$unwind": "$pb_event" },
    {
        "$group": {
            "_id": {
                "event_date": "$pb_event.event_date",
                "event_type": "$pb_event.event_type" 
            },            
            "details": {
                "$push": {
                    "_id": "$_id",
                    "name": "$Name"
                }
            },
            "count": { "$sum": 1 }            
        }
    },    
    {
        "$group": {
            "_id": "$_id.event_date",            
            "data": {
                "$push": {
                    "event_type": "$_id.event_type",
                    "details": "$details",
                    "count": "$count"
                }
            }           
        }
    },
    {
        "$project": {
            "_id": 0,
            "event_date": "$_id",
            "data": 1
        }
    }
])
Run Code Online (Sandbox Code Playgroud)

在上面的管道中,第一步是$unwind运算符

{ "$unwind": "$pb_event" }
Run Code Online (Sandbox Code Playgroud)

当数据存储为数组时,这非常方便。当展开运算符应用于列表数据字段时,它将为应用展开的列表数据字段的每个元素生成一条新记录。它基本上使数据扁平化。

这是下一个管道阶段的必要操作,在该阶段中,您将通过解构的数组字段$group对展平文档进行分组,并且:pb_eventevent_dateevent_type

{
    "$group": {
        "_id": {
            "event_date": "$pb_event.event_date",
            "event_type": "$pb_event.event_type" 
        },            
        "details": {
            "$push": {
                "_id": "$_id",
                "name": "$Name"
            }
        },
        "count": { "$sum": 1 }            
    }
},
Run Code Online (Sandbox Code Playgroud)

管道$group运算符类似于 SQL 的GROUP BY子句。GROUP BY在 SQL 中,除非使用任何聚合函数,否则无法使用。同样,您也必须使用 MongoDB 中的聚合函数(称为累加器运算符)。您可以在此处阅读有关聚合函数的更多信息。

在此$group 操作中,逻辑使用累加器运算符计算计数聚合,即组中文档的总数$sum。在同一管道中,您可以使用为每个组返回表达式值数组的运算符来聚合name和子文档的列表。_id$push

前面的$group管道

{
    "$group": {
        "_id": "$_id.event_date",            
        "data": {
            "$push": {
                "event_type": "$_id.event_type",
                "details": "$details",
                "count": "$count"
            }
        }           
    }
}
Run Code Online (Sandbox Code Playgroud)

将通过分组进一步聚合来自最后一个管道的结果,这通过使用最后的管道阶段event_date创建新的数据列表来形成所需输出的基础$push$project

{
    "$project": {
        "_id": 0,
        "event_date": "$_id",
        "data": 1
    }
}
Run Code Online (Sandbox Code Playgroud)

通过将字段重命名_idevent_date并保留另一个字段来重塑文档字段。