Mongodb 聚合管道中嵌入文档集合中的参考文档字段
我试图在管道阶段合并两个数组字段,它们位于嵌入文档集合中。但我一直在研究如何引用嵌入文档的两个“内部”数组 藏品 预期结果 方法 到目前为止,我尝试的总体方法是: (带有2个硬编码阵列,用于测试) 这将产生预期的结果:Mongodb 聚合管道中嵌入文档集合中的参考文档字段,mongodb,mongodb-query,Mongodb,Mongodb Query,我试图在管道阶段合并两个数组字段,它们位于嵌入文档集合中。但我一直在研究如何引用嵌入文档的两个“内部”数组 藏品 预期结果 方法 到目前为止,我尝试的总体方法是: (带有2个硬编码阵列,用于测试) 这将产生预期的结果: [{ name : "first", docs : [ { a1 : ["a", "b"], a2 : ["c"],
[{
name : "first",
docs : [
{
a1 : ["a", "b"],
a2 : ["c"],
merged : ["hello", "world"] // <- OK
},
{
a1 : ["d", "e"],
a2 : ["f"],
merged : ["hello", "world"] // <- OK
}
]
},{
name : "second",
docs : [
{
a1 : [1.0, 2.0],
a2 : [3.0],
merged : ["hello", "world"] // <- OK
},
{
a1 : [4.0, 5.0],
a2 : [6.0],
merged : ["hello", "world"] // <- OK
}
]
}]
考虑
我不能使用更新
查询,因为不能更改原始文档。因此,这个必须在聚合管道中实现
在这一点上,我尽量避免使用unwind
操作,因为这将对性能产生重大影响。实际文档的根包含相当多的(变量)字段;在放松
后进行分组
阶段相当复杂。
(为了便于阅读,该示例已大大简化)
我正在使用MongoDBv4.4
您可以执行以下操作
首先$unwind
展开文档数组
因为a1和a2是动态的,所以我们将其放入数组中。(如果我们使用此选项,可以在输出中构造多个动态键)
然后$reduce
将数据添加到数组中
并将其重新组合以获得所需的输出
聚合脚本是
[
{
"$unwind": "$docs"
},
{
$project: {
name: 1,
data: {
$objectToArray: "$docs"
}
}
},
{
$project: {
name: 1,
data: {
$reduce: {
input: "$data",
initialValue: [],
in: {
$concatArrays: [
"$$this.v",
"$$value"
]
}
}
}
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
docs: {
$push: {
merged: "$data"
}
}
}
}
]
工作我想这样就可以了,如果我缺少什么,请告诉我:
db.collection.aggregate([{
$project: {
_id: 0,
"name": 1,
"docs": {
$function: {
body: function(docs) {
docs.forEach(function(doc) {
var merged = [];
Object.keys(doc).forEach(function(k) {
merged = merged.concat(doc[k]);
delete doc[k];
});
doc.merged = merged;
});
return docs;
},
args: [ "$docs" ],
lang: "js"
}
}
}
}])
我尽量避免展开
,因为这会迫使我重新组合文档。这更复杂,因为我的实际文档在其根目录下包含许多(变量)属性。问题更多的是关于如何引用嵌入文档中的字段。我也尝试了不同的方法,但我觉得无论如何都需要使用group。但您可以按$$ROOT
对其进行分组,并用数据替换。但我急切地等待一个不使用unwind和groupI的回复,我不确定,但也许可以帮上忙——因为您使用的是MongoDB v4.4+。我希望它可以通过内置功能解决。但是$函数
操作符完美地解决了这个问题,对性能的影响可以接受。谢谢
[{
name : "first",
docs : [
{
a1 : ["a", "b"],
a2 : ["c"],
merged : ["hello", "world"] // <- OK
},
{
a1 : ["d", "e"],
a2 : ["f"],
merged : ["hello", "world"] // <- OK
}
]
},{
name : "second",
docs : [
{
a1 : [1.0, 2.0],
a2 : [3.0],
merged : ["hello", "world"] // <- OK
},
{
a1 : [4.0, 5.0],
a2 : [6.0],
merged : ["hello", "world"] // <- OK
}
]
}]
// Using the "$" reference causes following error:
// Invalid $set :: caused by :: FieldPath field names may not start with '$'.
{
$set: {
"docs.merged": { $concatArrays: ["$docs.$.a1", "$docs.$.a2"] }
}
}
// $$this is only available with a MAP operator
{
$set: {
"docs.merged": { $concatArrays: ["$$this.a1", "$$this.a2"] }
}
}
[
{
"$unwind": "$docs"
},
{
$project: {
name: 1,
data: {
$objectToArray: "$docs"
}
}
},
{
$project: {
name: 1,
data: {
$reduce: {
input: "$data",
initialValue: [],
in: {
$concatArrays: [
"$$this.v",
"$$value"
]
}
}
}
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
docs: {
$push: {
merged: "$data"
}
}
}
}
]
db.collection.aggregate([{
$project: {
_id: 0,
"name": 1,
"docs": {
$function: {
body: function(docs) {
docs.forEach(function(doc) {
var merged = [];
Object.keys(doc).forEach(function(k) {
merged = merged.concat(doc[k]);
delete doc[k];
});
doc.merged = merged;
});
return docs;
},
args: [ "$docs" ],
lang: "js"
}
}
}
}])