MongoDB删除重复的子文档

时间:2015-03-12 20:16:59

标签: javascript mongodb mongoose mongodb-query aggregation-framework

这是我的架构的设计。 (显示1个文件,数据总计数千)。一切都在同一个系列中。

文件1:

{
    pageNumber: 0,
    results: [
        {
            jobkey: "AAA", 


        },
           {
            jobkey: "BBB",


        },
           {
            jobkey: "CCC",


        }
    ]
}

文件2:

{
    pageNumber: 0,
    results: [
        {
            jobkey: "RRR", 


        },
           {
            jobkey: "VVV",


        },
           {               //This Entire Object needs to be removed
            jobkey: "AAA", //Duplicate jobkey value of document 1
                           //remaining objects in array should stay

        }
    ]
}

每个文档都有一个结果键,它接收一个对象数组。这些对象中的每一个都有一个jobkey和相应的值。在给定的结果数组中,没有两个jobkeys具有相同的值。

问题:

每当jobkey值在数据库中出现多次时,我都需要删除其中一个重复对象。多个结果数组中可能存在相同的jobkey值。

我一直无法找到在mongo shell或mongoose中完成此操作的方法。

1 个答案:

答案 0 :(得分:1)

这对我来说似乎是一个奇怪的“重复”定义,因为这些值实际上是在单独的文档中。接下来,如果没有实质性地查询整个集合,在将其添加到目标文档之前查看该值是否存在于任何文档中,您将无法在未来的操作中强制执行此操作。

为了检测并删除“重复”,你必须采取这样的操作:

db.collection.aggregate([
    // Match only where array has content
    { "$match": { "results.0": "$exists } },

    // Unwind the array
    { "$unwind": "$results" },

    // Group the keys with counts keep the doc _id's
    { "$group": {
        "_id": "$results.jobkey",
        "_ids": { "$push": "$_id" },
        "count": { "$sum": 1 }
    }},

    // Filter only duplicate matches
    { "$match": { "count": { "$gt": 1 } }
]).forEach(function(doc) {
    doc._ids.shift();    // remove the first element
    db.collection.update(
        { "_id": { "$in": doc._ids } },
        { "$pull": { "results": { "jobkey": doc._id } } },
        { "multi": true }
    )
})

基本上确定您认为是“重复”的术语列表,然后迭代该列表以删除其他文档的数组中的文档,这些文档被认为包含另一个文档中存在的一个“重复”。 / p>

这也正在任意判断发现“重复”值的“第一”文档是需要保留的位置。您可以在$sort之前添加$group,如果您要保留它的位置与其他一组规则相匹配。

保留列表是因为只有那些不是“第一”文档的文档才是您要更新的文档。当然,后来的$match过滤掉了在分组键中只出现一次相同值的任何结果。

在迭代这些结果时,您只需从列表中“删除”该“第一个”文档_id,因为这是您保留的文档。后续.update()操作仅匹配列表中的“重复”文档。语句的“更新”部分使用$pull将与指定值匹配的数组元素移除到查询匹配的所有文档中的jobkey。

如果您的目的是保持这些子文档元素具有“唯一”的jobkey值,那么您的用例可能更适合将这些文档存储在另一个集合中,并且只保留对父级数组中的那些文档的引用。在单独的集合中,您可以在索引上使用“唯一约束”来阻止插入重复值。