英文:
pymongo mongodb: how to update the field of a record only if it already exists?
问题
假设我有一个如下所示的Mongo文档,其中包含两条记录:
[
{"a": "a1", "b": "b1", "c": "c1", "d": "d1"},
{"a": "a2", "b": "b2", "c": "c2", "d": "d2"}
]
假设我有一个数据字典如下:
{"c": "c3", "d": "d3", "e": "e3"}
如果字段已存在,我想要找到并更新一条记录,示例如下:
_collection.find_one_and_update(
{"a": "a1", "b": "b1"},
{"$set": data},
# 这里有一些选项?
)
我希望结果如下所示:
[
{"a": "a1", "b": "b1", "c": "c3", "d": "d3"},
{"a": "a2", "b": "b2", "c": "c2", "d": "d2"}
]
而不是:
[
{"a": "a1", "b": "b1", "c": "c3", "d": "d3", "e": "e3"},
{"a": "a2", "b": "b2", "c": "c2", "d": "d2"}
]
我应该如何做到这一点?关键是data
是动态的,可能包含无法控制的字段(键值对)。
您可以使用以下方法来实现所需的更新操作,即只更新已存在的字段,而不添加新字段:
_collection.update_one(
{"a": "a1", "b": "b1"},
{"$set": {key: value for key, value in data.items() if key in {"c", "d"}}}
)
这将只更新data
中在文档中已存在的字段("c"和"d"),而不会添加新字段。
英文:
suppose I have a mongo document as below that has two records:
[
{"a": "a1", "b": "b1", "c": "c1", "d": "d1"},
{"a": "a2", "b": "b2", "c": "c2", "d": "d2"}
]
and suppose I have a data dict as below:
{"c": "c3", "d": "d3", "e": "e3"}
I want to find one and update if the field already exists:
_collection.find_one_and_update(
{"a": "a1", "b": "b1"},
{"$set": data},
# SOME OPTIONS HERE?
)
I want the result to be
[
{"a": "a1", "b": "b1", "c": "c3", "d": "d3"},
{"a": "a2", "b": "b2", "c": "c2", "d": "d2"}
]
not
[
{"a": "a1", "b": "b1", "c": "c3", "d": "d3", "e", "e3"},
{"a": "a2", "b": "b2", "c": "c2", "d": "d2"}
]
How should I do this? The point is that data
is dynamic and might contain fields (key-value pairs) out of control.
答案1
得分: 2
这是您提供的代码的翻译部分:
// 在使用聚合管道进行更新的更干净实现的[这里](https://mongoplayground.net/p/GI-DMclMm4z)。
db.collection.update(
{
"a": "a1",
"b": "b1"
},
[
{
$set: {
merged: {
"$mergeObjects": [
"$$ROOT",
{
"c": "c3",
"d": "d3",
"e": "e3"
}
]
}
}
},
{
$set: {
merged: {
"$objectToArray": "$merged"
},
rootArray: {
"$objectToArray": "$$ROOT"
}
}
},
{
$set: {
merged: {
// 如果键存在于原始文档中,则过滤合并/更新结果
"$filter": {
"input": "$merged",
"as": "m",
"cond": {
"$in": [
"$$m.k",
"$rootArray.k"
]
}
}
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$arrayToObject": "$merged"
}
}
}
]
)
// 对于通用解决方案,可以首先使用“$mergeObjects”对提供的负载和“$$ROOT”文档执行无条件更新。
// 然后使用“$objectToArray”将更新结果和“$$ROOT”文档转换为键值对数组。
// 使用“$filter”在更新结果中使用“$in”来查看键是否在原始文档中。
// 最后,使用“$merge”将结果更新回集合中。
db.collection.aggregate([
{
$match: {
"a": "a1",
"b": "b1"
}
},
// 首先计算无条件更新/合并结果
{
$set: {
merged: {
"$mergeObjects": [
"$$ROOT",
{
"c": "c3",
"d": "d3",
"e": "e3"
}
]
}
}
},
{
$set: {
merged: {
"$objectToArray": "$merged"
},
rootArray: {
"$objectToArray": "$$ROOT"
}
}
},
{
$set: {
merged: {
// 如果键存在于原始文档中,则过滤合并/更新结果
"$filter": {
"input": "$merged",
"as": "m",
"cond": {
"$in": [
"$$m.k",
"$rootArray.k"
]
}
}
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$arrayToObject": "$merged"
}
}
},
{
"$merge": {
"into": "collection",
"on": "_id"
}
}
])
英文:
Edit: Thanks to @cmgchess' comment, here is a cleaner implementation with update with aggregation pipeline.
db.collection.update({
"a": "a1",
"b": "b1"
},
[
{
$set: {
merged: {
"$mergeObjects": [
"$$ROOT",
{
"c": "c3",
"d": "d3",
"e": "e3"
}
]
}
}
},
{
$set: {
merged: {
"$objectToArray": "$merged"
},
rootArray: {
"$objectToArray": "$$ROOT"
}
}
},
{
$set: {
merged: {
// filter the merge/update result if the key exists in original document
"$filter": {
"input": "$merged",
"as": "m",
"cond": {
"$in": [
"$$m.k",
"$rootArray.k"
]
}
}
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$arrayToObject": "$merged"
}
}
},
])
For a generic solution, you can first use $mergeObjects
to perform an unconditional update of the payload you are giving and the $$ROOT
document. Then use $objectToArray
to convert the update result and $$ROOT
document to arrays of k-v tuples. Perform a $filter
on the update result with $in
to see if the key is in the original document. Finally, use $merge
to update the result back into the collection.
db.collection.aggregate([
{
$match: {
"a": "a1",
"b": "b1"
}
},
// compute the unconditional update/merge result first
{
$set: {
merged: {
"$mergeObjects": [
"$$ROOT",
{
"c": "c3",
"d": "d3",
"e": "e3"
}
]
}
}
},
{
$set: {
merged: {
"$objectToArray": "$merged"
},
rootArray: {
"$objectToArray": "$$ROOT"
}
}
},
{
$set: {
merged: {
// filter the merge/update result if the key exists in original document
"$filter": {
"input": "$merged",
"as": "m",
"cond": {
"$in": [
"$$m.k",
"$rootArray.k"
]
}
}
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$arrayToObject": "$merged"
}
}
},
{
"$merge": {
"into": "collection",
"on": "_id"
}
}
])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论