MongoDB 将字符串数组聚合连接到单个字符串
MongoDB Aggregation join array of strings to single string
我们正在尝试 'join' 将字符串数组 'join' 聚合为单个字符串。
给定以下数据集:
集合 1:
{
id: 1234,
field: 'test'
}
集合 2:
{
id: 1111,
collection1_id: 1234,
name: 'Max'
},
{
id: 1112,
collection1_id: 1234,
name: 'Andy'
}
当前结果(经过查找等):
{
id: 1234,
field: 'test',
collection2: ['Max', 'Andy']
}
想要的结果:
{
id: 1234,
field: 'test',
collection2: 'Max, Andy'
}
是否可以通过某种方式将 'collection2' 连接到单个字符串?我们试过 $concat
但它只接受字符串。
要展平这个数组,您需要将进程转移到客户端。
mongo 将在新版本中提供一些新的扁平化选项,但据我所知,它将是算术选项(平均、最小、最大....)。
你走在正确的轨道上。
只需在您的 $project
阶段添加 $reduce over $concat。
'collection2': {
'$reduce': {
'input': '$collection2',
'initialValue': '',
'in': {
'$concat': [
'$$value',
{'$cond': [{'$eq': ['$$value', '']}, '', ', ']},
'$$this']
}
}
}
注意:我们使用 $cond 来防止串联中出现前导 ,
。
您也可以在 $reduce
之前使用 $substrCP 作为 $cond
.
的替代方法
从 Mongo 4.4
开始,$group
阶段有一个新的聚合运算符 $accumulator
允许在文档分组时自定义累积:
// { "collectionId" : 1234, "name" : "Max" }
// { "collectionId" : 876, "name" : "Rob" }
// { "collectionId" : 1234, "name" : "Andy" }
db.collection.aggregate([
{ $group: {
_id: "$collectionId",
names: {
$accumulator: {
accumulateArgs: ["$name"],
init: function() { return [] },
accumulate: function(names, name) { return names.concat(name) },
merge: function(names1, names2) { return names1.concat(names2) },
finalize: function(names) { return names.join(",") },
lang: "js"
}
}
}}
])
// { "_id" : 876, "names" : "Rob" }
// { "_id" : 1234, "names" : "Max,Andy" }
累加器:
- 场上累积
name
(accumulateArgs
)
- 初始化为空数组(
init
)
- 通过将新名称连接到已出现的名称(
accumulate
和 merge
)来累积
- 最后将所有名称连接成一个字符串 (
finalize
)
有时最容易使用JavaScript:
db.getCollection('Collection1').aggregate([
{
$lookup:
{
from: 'Collection2',
localField: 'id',
foreignField: 'collection1_id',
as: 'col2'
}
}]).map((e) => ({
id: e.id,
field: e.field,
collection2: Array.isArray(e.col2) &&
e.col2.reduce((arr, el) => {
arr.push(el.name);
return arr;
}, []).join(', ')
}))
我们正在尝试 'join' 将字符串数组 'join' 聚合为单个字符串。
给定以下数据集:
集合 1:
{
id: 1234,
field: 'test'
}
集合 2:
{
id: 1111,
collection1_id: 1234,
name: 'Max'
},
{
id: 1112,
collection1_id: 1234,
name: 'Andy'
}
当前结果(经过查找等):
{
id: 1234,
field: 'test',
collection2: ['Max', 'Andy']
}
想要的结果:
{
id: 1234,
field: 'test',
collection2: 'Max, Andy'
}
是否可以通过某种方式将 'collection2' 连接到单个字符串?我们试过 $concat
但它只接受字符串。
要展平这个数组,您需要将进程转移到客户端。
mongo 将在新版本中提供一些新的扁平化选项,但据我所知,它将是算术选项(平均、最小、最大....)。
你走在正确的轨道上。
只需在您的 $project
阶段添加 $reduce over $concat。
'collection2': {
'$reduce': {
'input': '$collection2',
'initialValue': '',
'in': {
'$concat': [
'$$value',
{'$cond': [{'$eq': ['$$value', '']}, '', ', ']},
'$$this']
}
}
}
注意:我们使用 $cond 来防止串联中出现前导 ,
。
您也可以在 $reduce
之前使用 $substrCP 作为 $cond
.
从 Mongo 4.4
开始,$group
阶段有一个新的聚合运算符 $accumulator
允许在文档分组时自定义累积:
// { "collectionId" : 1234, "name" : "Max" }
// { "collectionId" : 876, "name" : "Rob" }
// { "collectionId" : 1234, "name" : "Andy" }
db.collection.aggregate([
{ $group: {
_id: "$collectionId",
names: {
$accumulator: {
accumulateArgs: ["$name"],
init: function() { return [] },
accumulate: function(names, name) { return names.concat(name) },
merge: function(names1, names2) { return names1.concat(names2) },
finalize: function(names) { return names.join(",") },
lang: "js"
}
}
}}
])
// { "_id" : 876, "names" : "Rob" }
// { "_id" : 1234, "names" : "Max,Andy" }
累加器:
- 场上累积
name
(accumulateArgs
) - 初始化为空数组(
init
) - 通过将新名称连接到已出现的名称(
accumulate
和merge
)来累积 - 最后将所有名称连接成一个字符串 (
finalize
)
有时最容易使用JavaScript:
db.getCollection('Collection1').aggregate([
{
$lookup:
{
from: 'Collection2',
localField: 'id',
foreignField: 'collection1_id',
as: 'col2'
}
}]).map((e) => ({
id: e.id,
field: e.field,
collection2: Array.isArray(e.col2) &&
e.col2.reduce((arr, el) => {
arr.push(el.name);
return arr;
}, []).join(', ')
}))