数组

时间:2017-01-13 09:26:14

标签: 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"
        }
    ]
}

现在,我希望event_date上的群组结果在event_type上的群组之后。 event_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
        }
    ]
}

1 个答案:

答案 0 :(得分:1)

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

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
        }
    }
])

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

{ "$unwind": "$pb_event" }

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

这是下一个管道阶段的必要操作, $group 步骤,您可以通过解构的pb_event数组字段event_date对展平的文档进行分组, event_type

{
    "$group": {
        "_id": {
            "event_date": "$pb_event.event_date",
            "event_type": "$pb_event.event_type" 
        },            
        "details": {
            "$push": {
                "_id": "$_id",
                "name": "$Name"
            }
        },
        "count": { "$sum": 1 }            
    }
},

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

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

前面的 $group 管道

{
    "$group": {
        "_id": "$_id.event_date",            
        "data": {
            "$push": {
                "event_type": "$_id.event_type",
                "details": "$details",
                "count": "$count"
            }
        }           
    }
}

将通过对event_date进行分组来进一步汇总最后一个管道的结果,{ "$project": { "_id": 0, "event_date": "$_id", "data": 1 } } 通过使用 $push 创建新数据列表来形成所需输出的基础,然后最后的 $project 管道阶段

_id

通过将event_date字段重命名为array并保留其他字段来重新整形文档字段。