【问题标题】:MongoDB Removing Duplicate subdocumentsMongoDB 删除重复的子文档
【发布时间】:2015-05-15 04:17:04
【问题描述】:

这是我的架构的设计。 (显示了 1 个文档,以 db 为单位总计数千个)。一切都在同一个集合中。

文档 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 值可能出现在多个结果数组中。

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

【问题讨论】:

  • 作业密钥不能在一个文档中重复中,或者在不同文档中重复?不同文档中可以有相同的jobkey吗?
  • 另外,您需要从现有文档中删除重复项,还是只删除未来的?
  • 我只需要从现有数据库中删除重复项。我以后不会添加任何其他记录。上面的代码示例显示了一个文档。该文档中没有任何重复项。但是下一个文档可能有一个结果键,其中包含与上面列出的值重复的作业键。让我知道这是否有意义?我将努力粘贴一个确切的例子。

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


【解决方案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 }
    )
})

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

这也是在任意判断,发现“重复”值的“第一个”文档就是它需要停留的地方。如果您要保存它的位置符合其他规则集,您可以在$group 之前添加$sort

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

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

如果您的持续意图是使用“唯一”作业键值保留这些子文档元素,那么您的用例可能更适合将这些文档存储在另一个集合中,并且只保留对这些文档的引用在父数组中.然后,您可以在单独的集合中对索引使用“唯一约束”,以阻止插入重复值。

【讨论】:

  • 很棒的帖子。我同意这不是数据库的理想格式。问题是我正在为一个学校项目从 Indeed.com api 中提取数据,我每页可以获得的最大结果数是 25。所以每次我拉取数据时,我最终都会创建一个新文档。理想情况下,我希望有一个仅包含在结果数组中找到的信息的数据库,并一起删除父文档。唯一的问题是我需要保留父文档中的一个键/值对。
猜你喜欢
  • 1970-01-01
  • 2021-11-27
  • 2023-03-28
  • 2012-07-30
  • 1970-01-01
  • 2020-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多