【问题标题】:MongoDB Union and intersection in one call一次调用 MongoDB 并集和交集
【发布时间】:2026-01-31 17:00:02
【问题描述】:

我希望能够先进行联合,然后再进行交集。

我的文档结构:

{
    "_id" : 1,
    "items" : [ 
        52711, 
        201610, 
        273342, 
        279449, 
        511250
    ]
},
{
    "_id" : 2,
    "items" : [ 
        246421, 
        390200
    ]
}

此集合包含数千个上述形式的文档。 我想对一组文档执行联合,然后对从联合返回的集合执行交集。

例如:

Set 1 contains Id: [1,2,3,4,5]
Set 2 Contains Id: [3,4,5,6,7,8]
Set 3 Contains Id: [12,14,15,16,17]

它应该联合集合1和集合2和集合3中的所有列表项。然后对每个集合的结果进行交集。

到目前为止,我得到了如下的列表联合查询:

db.getCollection('Test').aggregate([
    { "$match": { "_id": { "$in": [1, 2, 3] } } },
    {
        "$group": {
            "_id": 0,
            "data": { "$push": "$items" }
        }
    },
    {
        "$project": {
            "items": {
                "$reduce": {
                    "input": "$data",
                    "initialValue": [],
                    "in": { "$setUnion": ["$$value", "$$this"] }
                }
            }
        }
    }
]) 

我现在也在 c# 中做这一切:

var group = new BsonDocument
                    {
                        { "_id", 0 },
                        {
                            "data", new BsonDocument {{"$push", "$items" } }

                        }
            };


            var project = new BsonDocument
            {
                {"items", new BsonDocument
                    {
                        { "$reduce", new BsonDocument
                            {
                                { "input", "$data"},
                                { "initialValue", new BsonArray()},
                                { "in", new BsonDocument { {"$setUnion", new BsonArray { "$$value", "$$this" }}}}
                            }
                        }
                    }
                }
            };



            var result = qaCollection.Aggregate()
                .Match(Builders<QAList>.Filter.In(x => x.Id, list))
                .Group(group)
                .Project(project)
                .FirstOrDefault();

此查询需要一些时间,因为它可能会返回大量数据。因此,如果我可以传递多个集合,它会合并单独的集合并将它们相交,这样数据就不会太大而无法返回。

提前谢谢..

【问题讨论】:

    标签: c# mongodb mongodb-query aggregation-framework mongodb-.net-driver


    【解决方案1】:

    根据answer given to question 24824361回答:

    在 MongoDB 中没有自动跨多个不同文档进行交集的功能。但是,可以通过这种方法计算交集:

    1. 记下您要相交的文档数
    2. 展开项目数组
    3. 统计每一项的出现次数
    4. 仅匹配那些出现次数与步骤 1 中的文档数相匹配的项目

    因此,例如,如果您在 3 个文档中获取项目的交集,那么您展开这些项目,计算每个项目出现的次数,并仅以出现 3 次的项目结束。

    当然,这只有在每个文档的 items 数组没有重复项时才有效。

    例如,如果源数据是这样的:

    db.test_unionintersection_*_42686348.insert([
        { "_id" : 1,
        "items" : [ 10, 20, 30, 40, 50 ]},
        { "_id" : 2,
        "items" : [ 20, 30, 40, 50, 60, 70, 80 ]},
        { "_id" : 3,
        "items" : [ 10, 40, 50, 60, 80 ]},
        { "_id" : 4,
        "items" : [ 20, 30, 40, 70, 80 ]}
    ])
    

    那么如果你想要文档 1,2,3 的交集(例如),你想要结果[40, 50]

    你可以这样计算:

    var document_ids = [1, 2, 3];
    var number_documents = document_ids.length;
    db.test_unionintersection_*_42686348.aggregate([
        { "$match": { "_id": { "$in": document_ids } } },
        { "$unwind": "$items"},
        { "$project" : { "_id" : 0, "item" : "$items"}},
        { "$group" : { _id: "$item", "count" : {$sum: 1}}},
        { "$match" : { "count" : number_documents}},
        { "$group" : { _id: "intersection", "items" : {$push: "$_id"}}},
    ]);
    

    给你结果:

    {
        "_id" : "intersection",
        "items" : [ 
            50.0, 
            40.0
        ]
    }
    

    【讨论】: