如何在 MongoDB 中保留重复项的同时进行递归查找
Posted
技术标签:
【中文标题】如何在 MongoDB 中保留重复项的同时进行递归查找【英文标题】:How to do recursive lookups while preserving duplicates in MongoDB 【发布时间】:2022-01-14 10:49:16 【问题描述】:我有一个这样的 mongo 数据库:
db.templates.insertMany( [
_id: 1, uuid: "1", name: "t1", related_templates: [ "2", "2" ] ,
_id: 2, uuid: "2", name: "t2", related_templates: [ "3", "3" ] ,
_id: 3, uuid: "3", name: "t3", related_templates: [ "4", "4" ] ,
_id: 4, uuid: "4", name: "t4",
] )
如您所见,数据表示一个树结构,但支持对同一个子节点的重复引用。我正在尝试从 t1 开始递归地获取整个树,包括重复引用。
结果如下所示:
"_id" : 1,
"uuid" : "1",
"name": "t1",
"related_templates" : [
"_id" : 2,
"uuid" : "2",
"name" : "t2",
"related_templates" : [
"_id" : 3,
"uuid" : "3",
"name" : "t3",
"related_templates" : [
"_id" : 4,
"uuid" : "4",
"name" : "t4"
,
"_id" : 4,
"uuid" : "4",
"name" : "t4"
]
,
"_id" : 3,
"uuid" : "3",
"name" : "t3",
"related_templates" : [
"_id" : 4,
"uuid" : "4",
"name" : "t4"
,
"_id" : 4,
"uuid" : "4",
"name" : "t4"
]
]
,
...(t2 repeats here)
]
Mongo 网站上建议的解决方案在这里:https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#std-label-unwind-example。 如果没有重复引用,则此解决方案效果很好,只需稍作修改,甚至还允许递归查找。但是,在我的情况下,我需要保留重复的查找
我也考虑过使用 unwind + group 的传统解决方案。该解决方案确实保留了重复项,但我还没有弄清楚如何递归地使用它。
我还考虑过使用 mongo 网站上的解决方案来获取不重复的内容,然后使用地图将获取的数据附加到原始的 related_templates 数组中。我认为这会起作用,但它似乎不是很优雅。
有没有我想念的优雅/更简单的解决方案来做到这一点?
【问题讨论】:
【参考方案1】:如果以后有人遇到这个问题,我会继续发布我想出的解决方案:
db.templates.aggregate([
"$match": 'uuid': "1"
,
'$lookup':
'from': "templates",
'let': 'uuids': "$related_templates",
'pipeline': [
'$match':
'$expr':
'$and': [
'$in': [ "$uuid", "$$uuids" ] ,
]
],
'as': "related_templates_objects"
,
$addFields:
"related_templates_objects_uuids":
$map:
input: "$related_templates_objects",
in: "$$this.uuid"
,
$addFields:
"related_templates":
$map:
input: "$related_templates",
in: "$arrayElemAt":[
"$related_templates_objects",
"$indexOfArray":["$related_templates_objects_uuids","$$this"]
]
,
"$project":"related_templates_objects":0,"related_templates_objects_uuids":0
])
总结:
-
进行不重复的查找,称为related_templates_objects。
创建一个与related_templates_objects 相同的数组,除了只提取uuid,称为related_templates_objects_uuids。
通过将related_templates 中的每个原始引用映射到related_templates_objects 中的正确对象(通过related_templates_objects_uuids 找到其索引)来创建所需的对象数组。
投影出用于创建新的related_templates 的原始两个中间字段。
当然,这个解决方案不是递归的。可以通过将外部管道的最后 4 个元素复制到内部管道中来递归一次。 然后按照我在项目中编码的相同复制和粘贴公式再递归 x 次。
希望解决方案对某人有所帮助。
【讨论】:
以上是关于如何在 MongoDB 中保留重复项的同时进行递归查找的主要内容,如果未能解决你的问题,请参考以下文章
Python List:这是在保留顺序的同时删除重复项的最佳方法吗? [复制]