如何在mongo中有效地通过查询删除文档?

时间:2012-04-04 15:21:40

标签: mongodb

我有一个查询,它选择要删除的文档。现在,我手动删除它们(使用python):

for id in mycoll.find(query, fields={}):
  mycoll.remove(id)

这似乎不是很有效。还有更好的方法吗?

修改

好的,我遗憾地忘记提及查询详情,因为这很重要。这是完整的python代码:

def reduce_duplicates(mydb, max_group_size):
  # 1. Count the group sizes
  res = mydb.static.map_reduce(jstrMeasureGroupMap, jstrMeasureGroupReduce, 'filter_scratch', full_response = True)
  # 2. For each entry from the filter scratch collection having count > max_group_size
  deleteFindArgs = {'fields': {}, 'sort': [('test_date', ASCENDING)]}
  for entry in mydb.filter_scratch.find({'value': {'$gt': max_group_size}}):
    key = entry['_id']
    group_size = int(entry['value'])
    # 2b. query the original collection by the entry key, order it by test_date ascending, limit to the group size minus max_group_size.
    for id in mydb.static.find(key, limit = group_size - max_group_size, **deleteFindArgs):
      mydb.static.remove(id)
  return res['counts']['input']

那么,它做了什么?它会将重复键的数量减少到每个键值最多max_group_size只保留最新记录。它的工作原理如下:

  1. 将数据MR设为(key, count)对。
  2. 使用count > max_group_size
  3. 迭代所有对
  4. key查询数据,同时按时间戳(最早的第一个)进行排序,并将结果限制为count - max_group_size最早的记录
  5. 删除所有找到的记录。
  6. 正如您所看到的,这完成了将重复项减少到最多N个最新记录的任务。所以,最后两个步骤是foreach-found-remove,这是我的问题的重要细节,它改变了一切,我必须更加具体 - 抱歉。

    现在,关于集合删除命令。它接受查询,但我的包括排序和限制。我可以删除吗?好吧,我试过了:

    mydb.static.find(key, limit = group_size - max_group_size, sort=[('test_date', ASCENDING)])
    

    这种尝试失败了。而且,它似乎是mongo.Observe:

    C:\dev\poc\SDR>python FilterOoklaData.py
    bad offset:0 accessing file: /data/db/ookla.0 - consider repairing database
    

    毋庸置疑,foreach-found-remove方法有效并产生预期结果。

    现在,我希望我已经提供了足够的背景,并且(希望)已经恢复了我失去的荣誉。

5 个答案:

答案 0 :(得分:34)

您可以使用查询删除所有匹配的文档

var query = {name: 'John'};
db.collection.remove(query);

但要小心,如果匹配文档的数量很多,您的数据库可能会降低响应速度。通常建议删除较小块的文档。

假设您有100k个要从集合中删除的文档。最好执行100个删除1k文档的查询,而不是删除所有100k文档的1个查询。

答案 1 :(得分:10)

您可以使用MongoDB脚本语言直接删除它:

db.mycoll.remove({_id:'your_id_here'});

答案 2 :(得分:2)

deleteMany()会更有效吗?我最近发现,{1}在100米文档集中的600万个文档中速度很慢。文档(https://docs.mongodb.com/manual/reference/method/db.collection.deleteMany

remove()

答案 3 :(得分:1)

cmd

中运行此查询
  

db.users.remove({" _id":ObjectId(" 5a5f1c472ce1070e11fde4af")});

如果您使用node.js,请编写此代码

User.remove({ _id: req.body.id },, function(err){...});

答案 4 :(得分:0)

如果有大量记录,我建议分页。

首先:获取要删除的数据计数:

-------------------------- COUNT --------------------------
var query= {"FEILD":"XYZ", 'DATE': {$lt:new ISODate("2019-11-10")}};
db.COL.aggregate([
    {$match:query},
    {$count: "all"}
  ])

第二:开始逐块删除:

-------------------------- DELETE --------------------------
var query= {"FEILD":"XYZ", 'date': {$lt:new ISODate("2019-11-10")}};
var cursor = db.COL.aggregate([
    {$match:query},
    { $limit : 5 }
  ])
cursor.forEach(function (doc){
    db.COL.remove({"_id": doc._id});
});

这应该更快:

var query={"FEILD":"XYZ", 'date': {$lt:new ISODate("2019-11-10")}};
var ids = db.COL.find(query, {_id: 1}).limit(5);
db.tags.deleteMany({"_id": { "$in": ids.map(r => r._id)}});