从MongoDB中删除包含在数组中的相同属性值的文档

时间:2015-05-31 23:17:26

标签: mongodb mongodb-query

我正在努力尝试从MongoDB 3.0数据库中删除共享数组中包含的2个属性值profiles.platformprofiles.handle的文档。

{
    _id: ID
    profiles: [{
        source: {},
        isProfile: Boolean,
        profile: {},
        demographics: {
            male: Number,
            female: Number
        },
        handle: String,
        platform: String
    }]
}

我尝试使用聚合框架来获取共享这些属性值的文档的_ids。

db.collection.aggregate([{
    "$group": {
        "_id": "$id",
        "duplicates": {
            "$addToSet": "$_id"
        },
        "handles": {
            "$addToSet": "$profiles.profile.handle",
            "$addToSet": "$profiles.profile.platform"
        },
        "count": {
            "$sum": 1
        }
    }
}, {
    "$match": {
        "count": {
            "$gt": 1
        }
    }
}, {
    "$out": "dupes"
}])

但那没用。我收到了一个错误

{
    "errmsg": "exception: insert for $out failed: { lastOp: Timestamp 1433113685000|1, connectionId: 4856701, err: \"BSONObj size: 56348873 (0x35BD0C9) is invalid. Size must be between 0 and 16793600(16MB) First element: _id: null\", code: 10334, n: 0, ok: 1.0 }",
    "code": 16996,
    "ok": 0
}

重复文件的例子
文件1

{
    _id: ID
    profiles: [{
        source: {},
        isProfile: true,
        profile: {},
        demographics: {
            male: 1,
            female: 0
        },
        handle:'tom', <--- specific property that is duplicated.
        platform:'myspace' <--- specific property that is duplicated.
    }]
}

文件2

{
    _id: ID
    profiles: [{
        source: {},
        isProfile: true,
        profile: {},
        demographics: {
            male: 1,
            female: 0
        },
        handle:'tom', <--- specific property that is duplicated.
        platform:'myspace' <--- specific property that is duplicated.
    }]
}

澄清: 我需要删除文档1,因为文档2与文档1具有相同的值。(删除顺序无关紧要)

1 个答案:

答案 0 :(得分:2)

删除碰巧包含具有与具有这些属性的共享数组项的另一文档匹配的特定属性的数组项的文档不是直接操作。

最好使用聚合框架和单独的批量写入操作的组合来执行此操作。这基本上是你想要的:

var bulk = db.collection.initializeOrderedBulkOp(),
    count = 0;

db.collection.aggregate([
    // Unwind the array
    { "$unwind": "$profiles" },

    // Group on required keys and count
    { "$group": {
        "_id": {
            "handle": "$profiles.handle",
            "platform": "$profiles.platform"
        },
        "count": { "$sum": 1 }
        "ids": { "$addToSet": "$_id" }
    }},

    // Filter anything that is not a duplicate
    { "$match": { "count": { "$gt": 1 } }},
]).forEach(function(doc) {
    doc.ids.shift();  // remove the first item to keep
    bulk.remove({ "_id": { "$in": doc.ids } });
    count++;

    // Execute only once every 1000 and re-initialize
    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.collecion.initializeOrderedBulkOp();
    }
});

// Clear any queued
if ( count % 1000 != 0 )
    bulk.execute();

或语言等效。基本上,首先要识别&#34;包含重复的文档然后&#34;保持&#34;来自比赛的一份文件或&#34;不包括&#34;从删除其中一个文件然后处理.remove()每个&#34;复制&#34;在列表中。

你可以通过额外的&#34;去重复&#34;文件本身,但这可能是一种相当安全的方法,因为几乎没有额外的开销。

虽然方便,但我个人不会在这里使用 $out 或尝试在汇总管道中完成所有工作。主要是因为&#34;保持&#34;这样一个分组中的整个文档可能会破坏16MB的BSON限制,而且尝试和#34;标记&#34;也会带来很多开销。重复的条目,只保留一个。

如果您有$out,那么您的MongoDB也支持批量操作,因此最好使用它们来减少流量。