如何计算 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" ]}
                            ]
                        }
                    }
                }
            }
        }
    }
])

Mongo Playground

由于聚合非常复杂,因此 运行在 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();