在我的查询中,我希望通过_id将相同的项目组合到一个字符串组中 这是我的文件
"_id" : ObjectId("59e955e633d64c81875bfd2f"),
"tag_id" : 1,
"client_id" : "10001"
"_id" : ObjectId("59e955e633d64c81875bfd30"),
"tag_id" : 1,
"client_id" : "10002"
我希望输出
"_id" : 1
"client_id" : "10001,10002"
答案 0 :(得分:2)
您可以使用聚合框架作为“两步”操作。这是首先通过$push
使用$group
管道将项目累积到数组中,然后在最终投影中对生成的数组使用$concat
$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"]
}
}
}
}
}
}}
])
我们也在这里应用$cond
以避免在结果中将空字符串与逗号连接,因此它看起来更像是分隔列表。
仅供参考有一个JIRA问题SERVER-29339确实要求$reduce
作为accumulator expression实施,以允许它直接在$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(",") }
)
)
如果您真的必须使用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 } }
)
当然,mapReduce
和_id
的特定value
形式的输出作为键组,但它基本上是输出。
我们使用[].concat.apply([],values.map(...))
,因为“reducer”的输出可以是“分隔字符串”,因为mapReduce
以大结果递增工作,因此reducer的输出可以在另一个传递中变为“输入” 。因此,我们需要预期会发生这种情况并相应地对待它。
答案 1 :(得分:0)
从Mongo 4.4
开始,$group
阶段有了一个新的聚合运算符$accumulator
,允许在文件分组时进行自定义累积:
// { "tag_id" : 1, "client_id" : "10001" }
// { "tag_id" : 1, "client_id" : "10002" }
// { "tag_id" : 2, "client_id" : "9999" }
db.collection.aggregate([
{ $group: {
_id: "$tag_id",
client_id: {
$accumulator: {
accumulateArgs: ["$client_id"],
init: function() { return [] },
accumulate: function(ids, id) { return ids.concat(id) },
merge: function(ids1, ids2) { return ids1.concat(ids2) },
finalize: function(ids) { return ids.join(",") },
lang: "js"
}
}
}}
])
// { "_id" : 2, "client_id" : "9999" }
// { "_id" : 1, "client_id" : "10001,10002" }
累加器:
client_id
(accumulateArgs
)字段上init
)accumulate
和merge
)来积累finalize
)