【问题标题】:Python MongoDB aggregation delete doc by _idPython MongoDB聚合按_id删除文档
【发布时间】:2020-05-11 18:06:57
【问题描述】:

嗯,我正在使用 python 和 MongoDB,但我在聚合方面遇到了很多问题。

我的主要收藏有这种结构

{
"_id": {
    "$oid": "5bef5692d0c24110b0004671"
},
"dateAdded": {
    "$date": "2018-10-16T23:45:22.974Z"
},
"phoneNumber": "xxxxxxxx",
"phoneType": "pay",
"duration": 0,
"apiCallsCount": 3,
"tenant": {
    "$oid": "5b3fd3f99a8f4e04900c4e17"
},
"sessionStatus": "EXPIRED"

}

我的第二个收藏有这个结构

{
    "_id": {
        "$oid": "5bf46869d0c2410decc4e050"
    },
    "dateAdded": {
        "$date": "2018-11-20T20:02:49.281Z"
    },
    "resolutionStatus": "Complete",
    "finalResult": "OK",
    "intention": "Query_one",
    "call": {
        "$oid": "5bef5692d0c24110b0004671"
    },
    "duration": 0,
    "dateExpired": {
        "$date": "2018-11-20T20:04:01.732Z"
    },
    "queryType": "phone",
    "tenant": {
        "$oid": "5b3fd3f99a8f4e04900c4e17"
    }
}

首先,我需要在特定日期之前从第一个集合中获取所有文档,接下来使用 _id 获取所有这些文档,我需要获取第二个集合中的所有文档(第一个集合中的 _id 与调用第二个集合)并将其从集合中删除。

我认为我需要查找,我的聚合看起来像这样,但不起作用。我不知道我需要什么来解决这个问题。

self.db.get_collection(first_collection).aggregate([
   {
      $lookup:
         {
              from: second_collection,
              localField: "_id",
              foreignField: "call",
              as: "inventory_docs"
          }
   }
])

【问题讨论】:

  • 所以您想删除second_collection 中的整个文档还是只调用字段?你的数据库版本是多少?
  • 我想删除集合中的所有文档,MongoDB 4.2.6 社区
  • 所以您想删除 second_collection 中的所有文档,这些文档在添加日期过滤 first_collection 后在 first_collection 中有引用?
  • 是的,没错

标签: python mongodb mongodb-query aggregation-framework pymongo


【解决方案1】:

聚合大量用于读取,但很少用于写入。因此,聚合$out$merge 中只有两个阶段能够将数据写入数据库 - 这在您的情况下没有用,尽管它们可能比使用普通.find() 和执行此操作不可行.deleteMany().

你可以分两步完成,试试下面的基本代码:

1) 首先从first_collection 中获取要从second_collection 中删除的所有文档中的_id

ids = list(self.db.get_collection(first_collection).find({dateAdded : {$lte : inputDate }},{ _id :1 })) // Use `$lte` or `$lt`.

2) 从second_collection 中删除所有文档,其中call 字段的值存在于上述步骤中返回的任何ids 中:

from bson.objectid import ObjectId

if ids:  /** Checking to only execute this deletion operation when ids is not empty */
   convertedIds = [] // From Step 1, `ids` is an arrays of strings, We need to convert back to type `ObjectId()`'s to match with `call` field in DB.
   for id in ids:
       convertedIds.append(ObjectId(id))
   deletedDocs = self.db.get_collection(second_collection).delete_many({ call : {$in : convertedIds }});
   print(deletedDocs.deleted_count) // Just give no.of docs deleted

以防万一您想退回已删除的文档,请尝试使用 .findAndModify() 而不是 .deleteMany()。我认为 pymongo 的 .findAndModify() 相当于 .find_and_modify() 已被弃用,您可能需要使用 .find_one_delete() 但为了使用它,您不能将数组传递给过滤器中的 call 字段,如上:@ 987654342@。因此,您需要在 ids 上进行迭代并执行 { call : id } - 但这会导致多次删除数据库调用 - 我不想这样做并且会坚持使用 .delete_many(),除非我真的需要返回已删除的文档信息。

参考: .delete_many(), .find_one_and_delete() & $in

【讨论】:

  • 我做了第一步,没问题,在第二步中,我有如下结构的convertedIds:``` [ObjectId('5c784a3ed0c24127589237e9'), ObjectId('5c784e7dd0c24127589237f9'), ObjectId ('5c784e97d0c2412758923802'),...] ``` 但是我的 delete_many 有问题,我的错误是:文件“C:\Users\madeleon\AppData\Local\Continuum\anaconda3\lib\site-packages\pymongo \helpers.py", line 203, in _raise_last_write_error raise WriteError(error.get("errmsg"), error.get("code"), error) pymongo.errors.WriteError: Missing expected field "locale"
  • 我只是更改为这个 deletedDocs = self.db.get_collection(second_collection).delete_many({ call : {$in : convertIds }}) 一个工作得很好,谢谢!该程序非常快地在 35 秒内删除超过 150,000 个文档,在我使用 for 循环之前,它需要超过 20 分钟
  • @maxdlr.7 :我的错我忘记删除用于 node.js 的.toArray() 和用于.find() 的投影{_id :1},在我的回答中修复了它:-)
猜你喜欢
  • 2021-06-29
  • 2015-03-28
  • 2020-12-31
  • 1970-01-01
  • 2015-05-08
  • 2021-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多