MongoDB 删除重复的子文档

MongoDB Removing Duplicate subdocuments

这是我的架构设计。 (显示 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 找到完成此任务的方法。

对我来说,这似乎是 "duplicate" 的一个奇怪定义,因为这些值实际上位于单独的文档中。随后,您将没有真正的方法在未来的操作中强制执行此操作,而无需在将其添加到目标文档之前实质上查询整个集合以查看该值是否存在于任何文档中。

为了检测并删除 "duplicates",您将不得不求助于这样的操作:

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 }
    )
})

基本上确定您认为是 "duplicate" 的术语列表,然后迭代该列表以删除其他文档数组中被认为包含 "duplicate" 的文档存在于另一个文档中。

这也是武断判断发现"duplicated"值所在的"first"文档就是需要停留的地方。如果您想保留它的地方符合其他一些规则,您可以添加 $sort before $group

保留该列表是因为只有不是 "first" 文档的文档才是您要更新的文档。当然,后面的 $match 会过滤掉所有在分组键中只出现一次相同值的结果。

在迭代这些结果时,您只需 "remove" "first" 记录列表中的 _id,因为这是您保留的那个。随后的 .update() 操作仅匹配列表中的 "duplicate" 文档。该语句的 "update" 部分使用 $pull 删除与查询匹配的所有文档中的指定值与 jobkey 匹配的数组元素。

如果您的持续意图是保留那些具有 "unique" jobkey 值的子文档元素,那么您的用例可能更适合将这些文档存储在另一个集合中并仅保留对这些文档的引用父数组。在单独的集合中,您可以在索引上使用 "unique constraint" 来阻止插入重复值。