0

使用 PyMongo,我将一个集合 (refer_docs) 中的 MongoDB 文档与另一个集合 (test) 中的文档进行内部连接,并且我想找到那些连接的每个文档中的字段值不匹配的文档,我想更新这些值。refer_docs 文档应该说明它指向的测试文档具有正确的文档类型。

我可以找到这些文档,但我想在不循环遍历聚合结果列表并一次运行更新的情况下进行更新。

是否有 Mongo/PyMongo 方法可以在更新中使用聚合管道作为查询,或者在聚合()中使用 $set?或者?

管道从带有文档的集合之间的连接开始,如下例所示:

import pymongo
mongo_client = MongoClient('localhost:27017')
osm_db = mongo_client.osm
refer_docs_col = osm_db["refer_docs"]
test_col = osm_db["test"]

# test collection:
test_col.insert_many(
[
 {'_id': '611868136', 'doc_type': 'way'},
 {'_id': '5792648632', 'doc_type': 'node'},
 {'_id': '611868133', 'doc_type': 'node'},
 {'_id': '1', 'doc_type': 'node'}
]
)

# refer_docs collection:
refer_docs_col.insert_many(
[
 {'_id': '8483444',
  'refs': [{'ref': '611868136', 'ref_type': 'way'},
           {'ref': '5792648632', 'ref_type': 'node'},
           {'ref': '611868133', 'ref_type': 'way'}],
  'doc_type': 'relation'}
]
)

现在,这是管道和更新集合的一次尝试,它本质上是循环遍历结果,但它不起作用:

pipeline = [
    { "$unwind" : "$refs" },
    {
        "$lookup" : {
            "from" : "test",
            "localField" : "refs.ref",
            "foreignField" : "_id",
            "as" : "ref_doc"
        }
    },
    { "$match" : { "ref_doc" : { "$ne" : [] } } },
    { "$unwind" : "$ref_doc"},
    { "$project" : { "_id" : 1, "refs" : 1, "ref_doc.doc_type" : 1, 
                     "cmp" : { "$cmp" : [ "$refs.ref_type",
                                          "$ref_doc.doc_type" ] } } },
    { "$match" : { "cmp" : { "$ne" : 0 } } },
]

result = [
 refer_docs_col.find_one_and_update( doc,
    { "$set" : { "refs.ref_type" : "$ref_doc.doc_type" } } ) \
 for doc in refer_docs_col.aggregate(pipeline)
]

refer_docs_col.find_one( { "_id" : "8483444" } )

这不起作用,但我想看到文档已更新,因此 ref "611586133" 的 ref_type 现在是 "node":

{'_id': '8483444',
 'refs': [{'ref': '611868136', 'ref_type': 'way'},
          {'ref': '5792648632', 'ref_type': 'node'},
          {'ref': '611868133', 'ref_type': 'node'}],
 'doc_type': 'relation'}
4

1 回答 1

0

这行得通。

在这里,我使用"refs" : mismatch["refs"]在过滤器中查找数组元素,并"refs.$"设置找到的数组元素。

for mismatch in result: # Loop aggregation result docs
    filtr = { "_id" : mismatch["_id"] ,
              "refs" : mismatch["refs"]}
    update = { "$set" : { "refs.$" : { 
        "ref" : mismatch["ref_doc"]["_id"],
        "ref_type" : mismatch["ref_doc"]["doc_type"] } } }
    doc = refer_docs_col.update_one(filtr, update)

refer_docs_col.find_one( { "_id" : "8483444" } )

输出:

{'_id': '8483444',
 'refs': [{'ref': '611868136', 'ref_type': 'way'},
  {'ref': '5792648632', 'ref_type': 'node'},
  {'ref': '611868133', 'ref_type': 'node'}],
 'doc_type': 'relation'}
于 2020-11-25T01:34:47.570 回答