如何从聚合结果更新 MongoDB 集合,在数组中设置值
How to update MongoDB collection from aggregation results, set values within array
使用 PyMongo,我将一个集合 (refer_docs) 中的 MongoDB 个文档与另一个集合(测试)中的文档进行内部连接,我想找到那些文档中的值来自连接的每个文档中的一个字段不匹配,我想更新这些值。 refer_docs 文档应该说明它指向的测试文档具有正确的文档类型。
我可以找到那些文档,但我想在不循环遍历聚合结果列表的情况下进行更新,并且 运行 一次更新一个。
是否有 Mongo/PyMongo 方法可以在更新中使用聚合管道作为查询,或者在 aggregate() 中使用 $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'}
这有效。
这里,我使用"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'}
使用 PyMongo,我将一个集合 (refer_docs) 中的 MongoDB 个文档与另一个集合(测试)中的文档进行内部连接,我想找到那些文档中的值来自连接的每个文档中的一个字段不匹配,我想更新这些值。 refer_docs 文档应该说明它指向的测试文档具有正确的文档类型。
我可以找到那些文档,但我想在不循环遍历聚合结果列表的情况下进行更新,并且 运行 一次更新一个。
是否有 Mongo/PyMongo 方法可以在更新中使用聚合管道作为查询,或者在 aggregate() 中使用 $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'}
这有效。
这里,我使用"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'}