shi*_*wan 9 group-by concat mongodb aggregation-framework
我想对记录进行分组并_id通过组合client_id值来创建一个字符串。
以下是我的文档示例:
{
"_id" : ObjectId("59e955e633d64c81875bfd2f"),
"tag_id" : 1,
"client_id" : "10001"
}
{
"_id" : ObjectId("59e955e633d64c81875bfd30"),
"tag_id" : 1,
"client_id" : "10002"
}
Run Code Online (Sandbox Code Playgroud)
我想要这个输出:
{
"_id" : 1
"client_id" : "10001,10002"
}
Run Code Online (Sandbox Code Playgroud)
您可以使用聚合框架作为“两步”操作来完成此操作。首先通过$pushwith$group管道将项目累积到数组中,然后在最终投影中对生成的数组使用$concatwith :$reduce
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
{ "$addFields": {
"client_id": {
"$reduce": {
"input": "$client_id",
"initialValue": "",
"in": {
"$cond": {
"if": { "$eq": [ "$$value", "" ] },
"then": "$$this",
"else": {
"$concat": ["$$value", ",", "$$this"]
}
}
}
}
}
}}
])
Run Code Online (Sandbox Code Playgroud)
我们$cond在这里还应用以避免在结果中将空字符串与逗号连接起来,因此它看起来更像是一个分隔列表。
仅供参考,有一个 JIRA 问题SERVER-29339确实要求$reduce将其实现为累加器表达式,以允许它直接在$group管道阶段使用。不太可能很快发生,但理论上它会取代$push上面的操作并使操作成为单个管道阶段。建议的语法示例位于 JIRA 问题上。
如果您没有$reduce(需要 MongoDB 3.4 ),则只需对游标进行后处理:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
Run Code Online (Sandbox Code Playgroud)
mapReduce如果您确实必须这样做,那么就会导致使用另一种选择:
db.collection.mapReduce(
function() {
emit(this.tag_id,this.client_id);
},
function(key,values) {
return [].concat.apply([],values.map(v => v.split(","))).join(",");
},
{ "out": { "inline": 1 } }
)
Run Code Online (Sandbox Code Playgroud)
当然,它以和作为键集的特定mapReduce形式输出,但它基本上是输出。_idvalue
我们[].concat.apply([],values.map(...))之所以使用“reducer”,是因为“reducer”的输出可以是“定界字符串”,因为mapReduce以增量方式处理大结果,因此“reducer”的输出可以成为另一遍的“输入”。因此,我们需要预料到这种情况可能会发生,并相应地对待它。
| 归档时间: |
|
| 查看次数: |
1736 次 |
| 最近记录: |