MongoDB 使用 ensureIndex 删除重复项,但保留最后一个条目而不是第一个条目

Posted

技术标签:

【中文标题】MongoDB 使用 ensureIndex 删除重复项,但保留最后一个条目而不是第一个条目【英文标题】:MongoDB drop duplicates with ensureIndex but keep the last entry not the first 【发布时间】:2015-02-18 11:17:35 【问题描述】:

我有一个重复的问题。

我正在尝试从 MongoDB 集合中删除所有重复项,问题是我不想保留第一个条目而是最后一个。

这是我保留第一个条目的方式:

db.CUDB.ensureIndex( CUid: 1 , unique: true, dropDups: true )

但我希望能够以相反的方式 insureIndex 并保留最后添加的条目而不是第一个。

最简单的方法是什么?

【问题讨论】:

【参考方案1】:

ensureIndex 不提供执行此操作的方法。它也没有告诉哪些值将被删除。

在您的情况下,我会尝试执行以下操作(肯定会比确保索引更慢)。 我还假设您有一些字段(在我的情况下为 created_at),这取决于您决定一个文档是否比另一个文档更旧):

var checked = ; // basically a hash, which ensures O(1) lookup
db.coll.find().sort(created_at: -1).forEach(function(o)
  if (o['CUid'] in checked)
    db.coll.remove(_id: o['_id']);
   else 
    checked[o['CUid']] = 1;
  
)

所以基本上我们以相反的顺序(最新的第一个)迭代您的所有文档,并检查我们是否已经看到您的CUid 字段。如果我们没有,则保留此文档原样并将其标记为已查看。如果稍后我们看到任何其他具有相同 CUid 的文档,我们可以将其删除。

您最终将对您的集合进行一次完整扫描,并为每个重复的元素进行N 额外的数据库调用。

反向排序将确保保存最新的元素。

附言

注意上述代码中的错误;我只是证明了它是正确的,不是 试过了。

然后告诉我进展如何。

P.P.S.如果您仍然无法对 mongo 中的所有集合进行排序,我会尝试在应用层执行此操作。基本上你会找到你所有的集合,用你想要的任何语言对它们进行排序,然后在那里也执行相同的逻辑。

【讨论】:

这看起来很棒,但我有一个小内存问题:Runner error: Overflow sort stage buffered data usage of 33578371 bytes exceeds internal limit of 33554432 bytes 另外,数据库有大约 300k 条目,大约 1.6GB :-s @Eek 这是一个大问题:-)。这意味着没有足够的内存来对所有集合进行排序。可能有帮助的是在created_at 的模拟上创建一个索引,因为没有索引你不能使用超过 64MB(令我惊讶的是,在你的情况下它在 32MB 后关闭)

以上是关于MongoDB 使用 ensureIndex 删除重复项,但保留最后一个条目而不是第一个条目的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB ensureIndex 是不是执行重建?

MongoDB 学习笔记之 索引

MongoDB中喜欢的EnsureIndex

MongoDB创建索引

mongodb TTL不删除文档

mongodb TTL不删除文档