Concat字符串(按组) [英] Concat String by Group
问题描述
我想按_id
对记录进行分组,并通过组合client_id
值来创建字符串.
I want to group records by _id
and create a string by combining client_id
values.
以下是我的文档示例:
{
"_id" : ObjectId("59e955e633d64c81875bfd2f"),
"tag_id" : 1,
"client_id" : "10001"
}
{
"_id" : ObjectId("59e955e633d64c81875bfd30"),
"tag_id" : 1,
"client_id" : "10002"
}
我想要这个输出:
{
"_id" : 1
"client_id" : "10001,10002"
}
推荐答案
您可以使用聚合框架将其作为两步操作"进行操作.首先通过 $push
使用 $group
管道,然后使用 $concat
与
You can do it with the aggregation framework as a "two step" operation. Which is to first accumulate the items to an array via $push
withing a $group
pipeline, and then to use $concat
with $reduce
on the produced array in final projection:
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
以避免串联结果中带有逗号的空字符串,因此它看起来更像是定界列表.
We also apply $cond
here to avoid concatenating an empty string with a comma in the results, so it looks more like a delimited list.
仅供参考,JIRA问题 SERVER-29339 确实要求 $reduce
可以作为 $group
管道阶段.不太可能很快发生,但是从理论上讲它将取代 $push
中的内容,并使该操作成为单个管道阶段.提议的示例语法在JIRA问题上.
FYI There is an JIRA issue SERVER-29339 which does ask for $reduce
to be implemented as an accumulator expression to allow it's use directly in a $group
pipeline stage. Not likely to happen any time soon, but it theoretically would replace $push
in the above and make the operation a single pipeline stage. Sample proposed syntax is on the JIRA issue.
如果您没有 $reduce
(需要MongoDB 3.4),然后只需处理游标:
If you don't have $reduce
( requires MongoDB 3.4 ) then just post process the cursor:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
然后使用 mapReduce
如果您确实必须:
Which then leads to the other alternative of doing this using mapReduce
if you really must:
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 } }
)
当然会以_id
和value
的特定mapReduce
形式作为键集输出,但基本上是输出.
Which of course outputs in the specific mapReduce
form of _id
and value
as the set of keys, but it is basically the output.
我们使用[].concat.apply([],values.map(...))
是因为"reducer"的输出可以是定界字符串",因为mapReduce
可以递增地工作并获得较大的结果,因此,reducer的输出可以在另一遍通过中成为"input".因此,我们需要期望这会发生并相应地进行处理.
We use [].concat.apply([],values.map(...))
because the output of the "reducer" can be a "delimited string" because mapReduce
works incrementally with large results and therefore output of the reducer can become "input" on another pass. So we need to expect that this can happen and treat it accordingly.
这篇关于Concat字符串(按组)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!