这不是很漂亮,但这就是我得到的,对我的策略的简要描述是最初创建两组节点。一个包含“连接”的节点(即 x=>y 和 y=>x 边都存在)。另一个是潜在的单节点。表示它们有一个或零个 x=>y 或 y=>x 边。
一旦实现这一点,我们要做的就是通过连接连接的节点来减少数组。
请注意,我完全相信这不是实现您想要的结果的“最佳”方式,因为我只是专注于完成它而没有过多考虑性能或冗余。话虽如此,我将自己定义为 Mongo 爱好者,我肯定会说我对此有点挣扎。对我来说,这通常是一个危险信号,表明我的架构或数据库解决方案是错误的(也许使用图形数据库?)。同样,这些只是我的意见,我完全有可能只是纠结于这条管道。
值得一提的是,我考虑过使用$graphLookup 的方法,但是在完全连接或几乎完全连接的图上,这需要n 的深度使用,其中n= 节点数,尽管如此,我最终还是决定反对它如果您有任何可以将深度限制为某个常数的先验知识,则该方法可能是可行的。
db.collection.aggregate([
{
$unwind: {
path: "$similar_id",
preserveNullAndEmptyArrays: true
}
},
{
$addFields: {
similar_id: {
$ifNull: [
"$similar_id",
"$_id"
]
}
}
},
{
$sort: {
_id: 1,
similar_id: -1
}
},
{
$addFields: {
tmpId: {
$cond: [
{
$gt: [
"$similar_id",
"$_id"
]
},
[
"$_id",
"$similar_id"
],
[
"$similar_id",
"$_id"
]
]
}
}
},
{
$group: {
_id: "$tmpId",
sum: {
$sum: 1
}
}
},
{
$facet: {
single: [
{
$match: {
sum: 1
}
},
{
$unwind: "$_id"
},
{
$group: {
_id: null,
potentionals: {
$addToSet: "$_id"
}
}
}
],
clusters: [
{
$match: {
sum: 2
}
},
{
$group: {
_id: null,
edges: {
$addToSet: "$_id"
},
}
},
{
$project: {
all: {
$reduce: {
input: "$edges",
initialValue: [],
in: {
$setUnion: [
"$$this",
"$$value"
]
}
}
},
groups: {
$reduce: {
input: "$edges",
initialValue: [],
in: {
$cond: [
{
$gt: [
{
$size: {
$filter: {
input: "$$value",
as: "subgroup",
cond: {
$gt: [
{
$size: {
$setIntersection: [
"$$subgroup",
"$$this"
]
}
},
0
]
}
}
}
},
0
]
},
{
$map: {
input: "$$value",
as: "subgroup",
in: {
$cond: [
{
$gt: [
{
$size: {
$setIntersection: [
"$$subgroup",
"$$this"
]
}
},
0
]
},
{
"$setUnion": [
"$$this",
"$$subgroup"
]
},
"$$subgroup"
]
}
}
},
{
$concatArrays: [
"$$value",
[
"$$this"
]
]
}
]
}
}
}
}
}
]
}
},
{
$unwind: {
path: "$single",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$clusters",
preserveNullAndEmptyArrays: true
}
},
{
$project: {
groups: {
$concatArrays: [
"$clusters.groups",
{
$map: {
input: {
$filter: {
input: "$single.potentionals",
as: "pot",
cond: {
$eq: [
{
$size: {
$setIntersection: [
[
"$$pot"
],
"$clusters.all"
]
}
},
0
]
}
}
},
as: "single",
in: [
"$$single"
]
}
}
]
}
}
}
])
MongoPlayground