我需要集合中的每个文档仅在其内容不同时才更新,而不管嵌套列表中元素的顺序如何。
从根本上说,如果元素完全相同,而不管它们的顺序如何,那么两个版本应该是相同的。默认情况下,MongoDB不这样做。
def upsert(query, update):
# collection is a pymongo.collection.Collection object
result = collection.update_one(query, update, upsert=True)
print("\tFound match: ", result.matched_count > 0)
print("\tCreated: ", result.upserted_id is not None)
print("\tModified existing: ", result.modified_count > 0)
query = {"name": "Some name"}
update = {"$set": {
"products": [
{"product_name": "a"},
{"product_name": "b"},
{"product_name": "c"}]
}}
print("First update")
upsert(query, update)
print("Same update")
upsert(query, update)
update = {"$set": {
"products": [
{"product_name": "c"},
{"product_name": "b"},
{"product_name": "a"}]
}}
print("Update with different order of products")
upsert(query, update)
输出:
First update
Found match: False
Created: True
Modified existing: False
Same update
Found match: True
Created: False
Modified existing: False
Update with different order of products
Found match: True
Created: False
Modified existing: True
最后一次更新确实修改了文档,因为产品的顺序确实不同。
我确实找到了一个可行的解决方案,那就是比较查询文档内容的排序和新文档内容的排序。
感谢Zero Piraeus的response提供了一种简短方便的排序比较方法。
def ordered(obj):
if isinstance(obj, dict):
return sorted((k, ordered(v)) for k, v in obj.items())
if isinstance(obj, list):
return sorted(ordered(x) for x in obj)
else:
return obj
我应用它来比较文档的当前版本和新版本。如果它们的排序不同,我就应用更新。
new_update = {
"products": [
{"product_name": "b"},
{"product_name": "c"},
{"product_name": "a"}]
}
returned_doc = collection.find_one(query)
# Merging remote document with local dictionary
merged_doc = {**returned_doc, **new_update}
if ordered(returned_doc) != ordered(merged_doc):
upsert(query, {"$set": new_update})
print("Updated")
else:
print("Not Updated")
输出:
Not Updated
这是可行的,但是这依赖于python来做比较,在读和写之间引入了延迟。
有没有一种方法可以原子地完成它?或者,更好的是,有没有一种方法可以将MongoDB集合设置为采用某种"数组内的顺序无关紧要"的模式?
这是泛型实现的一部分。文档在其结构中可以有任何类型的嵌套。
2条答案
按热度按时间q8l4jmvw1#
这也应该保留
upsert
选项。这里有一个mongoplayground.net example来演示这个概念,您可以更改
"name"
的值来验证upsert
选项。我很好奇这个
update_one
的result
值是多少。wlwcrazw2#
EDIT:根据您的评论(以及与other question的相似之处),我建议:
了解它在playground example上的工作原理
原答复:
一个选项是使用更新的查询部分仅处理与条件匹配的文档:
了解它在playground example上的工作原理