我在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
}
]
}
答案 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
并保留其他字段来重新整形文档字段。