MongoDB聚合:将数组属性展平为根数组
Posted
技术标签:
【中文标题】MongoDB聚合:将数组属性展平为根数组【英文标题】:MongoDB aggregation: flatten array property into root array 【发布时间】:2021-01-25 02:42:57 【问题描述】:我正在开发一个使用$graphLookUp
递归查找cmets 线程的功能,我几乎拥有它。 (虽然有点复杂,但它确实有效!)
我需要的最后一步是:
不要将嵌套的 posteriorThread
作为根数组 ($$ROOT
) 的属性,而是将其合并到根本身。
const posteriorThread = await Comment.aggregate([
$match:
_id: post.threadDescendant
,
$graphLookup:
from: 'baseposts',
startWith: '$threadDescendant',
connectFromField: 'threadDescendant',
connectToField: '_id',
as: 'posteriorThread'
,
$unwind: '$posteriorThread'
,
$sort: 'posteriorThread.depth': 1
,
$group:
_id: '$_id',
posteriorThread: $push: '$posteriorThread' ,
root: $first: '$$ROOT'
,
$project:
'root.posteriorThread': 0
,
$replaceRoot:
newRoot:
$mergeObjects: [
posteriorThread: '$posteriorThread'
,
'$root'
]
]);
电流输出
OUTPUT: posteriorThread
[
_id: '5f7eab40575e6fc56ee07604',
onModel: 'BasePost',
depth: 1,
user: '5f5da45245c07cc06e51b09f',
text: 'thread 0',
isThread: true,
threadDescendant: '5f7eabad575e6fc56ee07607',
posteriorThread: [
_id: '5f7eabad575e6fc56ee07607',
onModel: 'Comment',
depth: 2,
user: '5f5da45245c07cc06e51b09f',
text: 'thread 1',
isThread: true,
threadDescendant: '5f7eac82575e6fc56ee07609'
,
_id: '5f7eac82575e6fc56ee07609',
onModel: 'Comment',
depth: 3,
user: '5f5da45245c07cc06e51b09f',
text: 'thread 2',
isThread: true
]
];
期望的输出
OUTPUT: posteriorThread
[
_id: '5f7eab40575e6fc56ee07604',
onModel: 'BasePost',
depth: 1,
user: '5f5da45245c07cc06e51b09f',
text: 'thread 0',
isThread: true,
threadDescendant: '5f7eabad575e6fc56ee07607'
,
_id: '5f7eabad575e6fc56ee07607',
onModel: 'Comment',
depth: 2,
user: '5f5da45245c07cc06e51b09f',
text: 'thread 1',
isThread: true,
threadDescendant: '5f7eac82575e6fc56ee07609'
,
_id: '5f7eac82575e6fc56ee07609',
onModel: 'Comment',
depth: 3,
user: '5f5da45245c07cc06e51b09f',
text: 'thread 2',
isThread: true
];
我可以在常规 js 中聚合后完成此操作,但我更愿意在聚合中完成所有操作。
需要替换的部分是 mergeObjects
位并替换为其他内容或 group
聚合并采取不同的策略,但我不确定该放置什么。
另外,如果您有任何其他建议来使这个更清洁,我会全力以赴。
提前致谢。
【问题讨论】:
【参考方案1】:真的很有挑战性。至少对我来说。而且非常有趣的案例。让我们试试我的解决方案。希望它有效..
db.test.aggregate([
// PREViosU STEPS YOU ALREADY DID
$group:
_id: "$_id",
items: $push: "$$ROOT",
subItems: $first: "$posteriorThread"
,
$project:
"items.posteriorThread": 0
,
$addFields:
allItems:
$concatArrays: ["$items", "$subItems"]
,
$group:
_id: null,
mergedItems: $push: "$allItems"
,
$unwind: "$mergedItems"
,
$unwind: "$mergedItems"
,
$replaceRoot:
newRoot: "$mergedItems"
])
【讨论】:
嘿,您的解决方案不起作用,因为 subItems 不是数组,因此无法连接,但它确实让我更接近了!我现在基本上有了它,但是$replaceRoot
仍然给我留下了一个嵌套数组,但这没什么大不了的,因为我可以在聚合后得到正确的解决方案。
如果您想查看我的最终解决方案,请查看我的答案。
很高兴听到您找到了解决方案。我不知道为什么我的解决方案不起作用。我实际上是在处理您的当前输出。这意味着您必须使用您已经执行的步骤,然后在现有阶段之后添加我的管道阶段。在您的当前输出中,后线程是一个项目数组。所以它应该奏效了。无论如何,我实际上将您的当前输出存储到一个集合中,然后我尝试了我的步骤。它给了我结果。无论如何,这个问题真的很有趣..
嗯,这很奇怪。是的,subItems 使用 $first 返回一个对象,所以当我转到 $concat 时,它会抛出错误,类似于“无法连接和对象”。但是,是的,我认为添加一个简单的线程功能将是几行代码,它变成了一整天的聚合和错误!再次感谢你的帮助;它真的让我走上了正确的道路。如果您想复制并粘贴我的答案,我会给您答案。
哈哈..不不。并不需要。请。我很高兴它真的有帮助!谢谢你的提问。老实说,我不知道该怎么做,这对我来说也是实验性的。问题陈述很有趣。所以我开始研究它,我也从中吸取了一些教训。【参考方案2】:
感谢@Sunil K Samanta 引导我朝着正确的方向前进。这不是最漂亮的解决方案,但它确实给了我正确的解决方案。
const posteriorThread = await Comment.aggregate([
$match:
_id: post.threadDescendant
,
$graphLookup:
from: 'baseposts',
startWith: '$threadDescendant',
connectFromField: 'threadDescendant',
connectToField: '_id',
as: 'posteriorThread'
,
$unwind: '$posteriorThread'
,
$sort: 'posteriorThread.depth': 1
,
$group:
_id: '$_id',
items: $push: '$$ROOT.posteriorThread' ,
root: $push: '$$ROOT' ,
,
,
$project:
items: 1,
root: $slice: ['$$ROOT.root', 0, 1] ,
,
,
$project:
'root.posteriorThread': 0,
,
,
$addFields:
allItems:
$concatArrays: ['$root', '$items'],
,
,
,
$replaceRoot:
newRoot:
full_posterior: '$$ROOT.allItems',
,
,
,
])
)[0].full_posterior;
【讨论】:
[0].full_posterior
是我们首先要避免的以上是关于MongoDB聚合:将数组属性展平为根数组的主要内容,如果未能解决你的问题,请参考以下文章