如何计算 mongo collection 中具有相交子 collection 的项目?
How can I count items in mongo collection that have intersecting subcollections?
对于我的 collection 中的每个项目,我需要查找具有相交子 collection 的其他项目的数量。例如,
鉴于此 collection
[{id:1,"sub":[1, 2, 3]},
{id:2,"sub":[2, 3, 4]},
{id:3,"sub":[4, 5, 6],
{id:4,"sub":[7, 8, 9]}]
预期结果是
[{id:1,"count":1},
{id:2,"count":2},
{id:3,"count":1},
{id:4,"count":0"}]
从纯 MongoDB 查询语言中的算法开始:您必须重组文档,以便每个文档包含它的初始 sub
数组和所有其他 sub
的数组值。为此,您需要 运行 $group along with $unwind. Then it becomes easy to just run $map with $setIntersect $filter out all empty and equal to self arrays and get the size using $size
db.collection.aggregate([
{
$group: {
_id: null,
current: { $push: "$$ROOT" },
all: { $push: "$sub" }
}
},
{
$unwind: "$current"
},
{
$project: {
id: "$current.id",
count: {
$size: {
$filter: {
input: {
$map: {
input: "$all",
in: { $setIntersection: [ "$$this", "$current.sub" ] }
}
},
cond: {
$and: [
{ $ne: [ "$$this", [] ] },
{ $ne: [ "$$this", "$current.sub" ]}
]
}
}
}
}
}
}
])
由于聚合非常复杂,因此 运行在 C# 中以强类型方式对其进行聚合是没有意义的。您所能做的就是使用 BsonDocument
class 来构建您的管道,例如:
var groupDef = new BsonDocument()
{
{ "_id", "" },
{ "current", new BsonDocument(){ { "$push", "$$ROOT" } } },
{ "all", new BsonDocument(){ { "$push", "$sub" } } },
};
var projectDef = BsonDocument.Parse(@"{
id: ""$current.id"",
_id: 0,
count: {
$size: {
$filter: {
input: {
$map: {
input: ""$all"",
in: {
$setIntersection: [
""$$this"",
""$current.sub""
]
}
}
},
cond: {
$and: [
{
$ne: [
""$$this"",
[]
]
},
{
$ne: [
""$$this"",
""$current.sub""
]
}
]
}
}
}
}
}");
var result = mongoDBCollection.Aggregate()
.Group(groupDef)
.Unwind("current")
.Project(projectDef)
.ToList();
对于我的 collection 中的每个项目,我需要查找具有相交子 collection 的其他项目的数量。例如, 鉴于此 collection
[{id:1,"sub":[1, 2, 3]},
{id:2,"sub":[2, 3, 4]},
{id:3,"sub":[4, 5, 6],
{id:4,"sub":[7, 8, 9]}]
预期结果是
[{id:1,"count":1},
{id:2,"count":2},
{id:3,"count":1},
{id:4,"count":0"}]
从纯 MongoDB 查询语言中的算法开始:您必须重组文档,以便每个文档包含它的初始 sub
数组和所有其他 sub
的数组值。为此,您需要 运行 $group along with $unwind. Then it becomes easy to just run $map with $setIntersect $filter out all empty and equal to self arrays and get the size using $size
db.collection.aggregate([
{
$group: {
_id: null,
current: { $push: "$$ROOT" },
all: { $push: "$sub" }
}
},
{
$unwind: "$current"
},
{
$project: {
id: "$current.id",
count: {
$size: {
$filter: {
input: {
$map: {
input: "$all",
in: { $setIntersection: [ "$$this", "$current.sub" ] }
}
},
cond: {
$and: [
{ $ne: [ "$$this", [] ] },
{ $ne: [ "$$this", "$current.sub" ]}
]
}
}
}
}
}
}
])
由于聚合非常复杂,因此 运行在 C# 中以强类型方式对其进行聚合是没有意义的。您所能做的就是使用 BsonDocument
class 来构建您的管道,例如:
var groupDef = new BsonDocument()
{
{ "_id", "" },
{ "current", new BsonDocument(){ { "$push", "$$ROOT" } } },
{ "all", new BsonDocument(){ { "$push", "$sub" } } },
};
var projectDef = BsonDocument.Parse(@"{
id: ""$current.id"",
_id: 0,
count: {
$size: {
$filter: {
input: {
$map: {
input: ""$all"",
in: {
$setIntersection: [
""$$this"",
""$current.sub""
]
}
}
},
cond: {
$and: [
{
$ne: [
""$$this"",
[]
]
},
{
$ne: [
""$$this"",
""$current.sub""
]
}
]
}
}
}
}
}");
var result = mongoDBCollection.Aggregate()
.Group(groupDef)
.Unwind("current")
.Project(projectDef)
.ToList();