我正在研究一些聚合管道。 我的上一步以以下两个文档结束:
{ x: 1, y: 60, z: 111}
和
{ x: 1, y: 90, z: 222}
我使用
x
作为 id
并希望将两个文档合并为:
{ x: 1, y1: { z: 111 }, y2: { z: 222} }
如有任何帮助,我们将不胜感激
我一直在尝试通过
"$group"
值来 x
它们,但最后仍然有数组;在 "$unwind"
步骤之后,又回到两个文档。
尽管我相信使用
$group
来保持 y
和 z
是最好的,但我提交此解决方案作为如何使用 $reduce
作为 for
循环以及 $arraytoObject
的力量的示例
在管道中动态构造 lval(字段)。
c=db.foo.aggregate([
// Only need value of z for later operations:
{$group: {_id: "$x", X: {$push: {z:"$z"}}}}
// Iterate over X and dynamically build k-v pairs for the
// upcoming arrayToObject. For efficiency, in the same stage
// ($project) we will use $getField to extact newX and leave us with just
// the reformed array, leaving out the stateful loop bits.
// Note we $project input X over existing X because there is no point
// in carrying the original array through the pipeline:
,{$project: {X: {$getField:{input: {$reduce: {
input: '$X',
initialValue: {
n:0, // counter state
newX:[] // the desired target data
},
in: {$let: {
vars: {qq:{$add:['$$value.n',1]}}, // n = n + 1
in: {
n: '$$qq', // must carry over count in the loop!
// This is the juice. Append to the array using
// $concatArrays. Note the dynamic construction
// of the field name k (for example, it will
// become 'y1', 'y2, etc. Note also v is set
// to a NEW object containing z as a field.
newX: {$concatArrays: [
'$$value.newX',
[ {'k':{$concat:['y',{$toString:'$$qq'}]},
'v':{z:'$$this.z'}
}
] ]}
}
}}
}}, field:'newX'}}
}}
/*
All data is now set up. To get a sense of what is happening,
comment out this last stage and look at the "before" output.
Astute observers will note that the pipeline stage above that
projects X could be eliminated and the contents used directly here:
{$replaceRoot: {newRoot: {$mergeObjects: [
{x: '$_id'},
{$arrayToObject: {$getField:{input: {$reduce: { ...
This eliminates a stage for efficiency but perhaps reduces clarity.
*/
,{$replaceRoot: {newRoot: {$mergeObjects: [
{x: '$_id'},
{$arrayToObject: '$X'}
]}
}}
]);