一次调用MongoDB Union和交集

时间:2017-03-09 03:52:53

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

我希望能够执行联合然后交叉。

我的文件结构:

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

此集合包含数千份上述表格的文件。 我想在文档集上执行Union,然后在Union返回的集合上执行交集。

例如:

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();

此查询需要一些时间,因为它可以返回大数据。因此,如果我可以传递多个集合并且它将联合单独的集合并将它们相交,那么这将非常好。因此数据不会很大而无法返回。

提前感谢..

1 个答案:

答案 0 :(得分:0)

根据answer given to question 24824361答案:

没有任何功能可以在几个不同的文档中自动在MongoDB中进行交集。但是,可以通过采用这种方法来计算交叉点:

  1. 记下您正在交叉的文件数量
  2. 展开项目数组
  3. 计算每个项目的出现次数
  4. 仅匹配其发生次数与步骤1中的文档数量匹配的项目
  5. 因此,例如,如果您正在处理3个文档中的项目的交集,那么您可以展开项目,计算每个项目出现的次数,并完成仅出现3次的项目。

    这仅在每个文档的items数组没有重复时才有效。

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

    db.test_unionintersection_stackoverflow_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_stackoverflow_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
        ]
    }