MongoDB:根据位置范围更新数组的子集
MongoDB: Update a subset of an array based on position range
我需要使用批量写入操作更新许多 MongoDB 文档中数组中的值(每个文档的新数组不同)。我的问题是:有没有办法根据元素位置范围更新数组值的子集,传递一个数组来用替换这些值?
这是我的文档结构:
{
year: 2020,
location_id: 1,
values: [1.2 0 0 5.2 1.02 8 0 0 0 0 1.2 4]
}
假设我想用这个新数组替换除第一个值之外的所有值:
[1 2 5.1 2 4 0 87 1 0.2 2 9]
即 'values' 应变为:
[1.2 1 2 5.1 2 4 0 87 1 0.2 2 9]
我知道如何完全替换数组:
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values': [1.2 1 2 5.1 2 4 0 87 1 0.2 2 9]}})
但是第一个选项要求我先查询集合以获取数组的第一个值。我想避免这种情况。
我也知道如何用 11 个单独的 updateone 命令逐一替换值(在 python 中):
col.bulk_write([UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.1': 1}}),
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.2': 2}}),
.... ,
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.11': 9}})],
ordered = False)
第二个选项意味着我将每天发送数百万个 UpdateOne 语句,因为我有数百万个文档每天都会更新,而且要更新的数组比这个简单示例中的数组大得多。我也不太喜欢。
请注意,一个相关的问题是:第二个选项是否会使我的服务器过载,或者它是否不会占用比第一个选项更多的资源?第一个选项将意味着使用 bulkwrite ,比如 300'000 个 updateOne 语句,每个修改一个 365 长数组,而第二个选项意味着 300'000*364 个 updateOne 语句,每个修改一个数组元素。
我希望能够做类似的事情:
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.1-end': [1 2 5.01 2 4 0 87 1 0.2 2 9]}})
即指定数组位置的范围,以替换为提供的数组。到目前为止,我找不到如何做到这一点。这将导致包含 300'000 个 updateOne 语句的批量写入,每个语句都准确地替换了需要替换的 364 个值。
注意:在这个例子中它取代了"all except the first value",但它也可能是"all except the last value"。可能还有 "replace elements at positions 4 to 9 by this array of length 6"。
我正在 python.
中编写代码
您可以使用聚合管道并将其用于更新:
db.collection.updateOne(
{'year': 2020, 'location_id': 1},
[{
$set: {
values: {
$concatArrays: [
[{ $arrayElemAt: ["$values", 0] }],
[1, 2, 5.1, 2, 4, 0, 87, 1, 0.2, 2, 9]
]
}
}
}]
)
对于像"replace elements at positions 4 to 9 by this array of length 6"这样的操作你也可以使用$slice
也是运算符$range may help, see
我需要使用批量写入操作更新许多 MongoDB 文档中数组中的值(每个文档的新数组不同)。我的问题是:有没有办法根据元素位置范围更新数组值的子集,传递一个数组来用替换这些值?
这是我的文档结构:
{
year: 2020,
location_id: 1,
values: [1.2 0 0 5.2 1.02 8 0 0 0 0 1.2 4]
}
假设我想用这个新数组替换除第一个值之外的所有值:
[1 2 5.1 2 4 0 87 1 0.2 2 9]
即 'values' 应变为:
[1.2 1 2 5.1 2 4 0 87 1 0.2 2 9]
我知道如何完全替换数组:
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values': [1.2 1 2 5.1 2 4 0 87 1 0.2 2 9]}})
但是第一个选项要求我先查询集合以获取数组的第一个值。我想避免这种情况。
我也知道如何用 11 个单独的 updateone 命令逐一替换值(在 python 中):
col.bulk_write([UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.1': 1}}),
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.2': 2}}),
.... ,
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.11': 9}})],
ordered = False)
第二个选项意味着我将每天发送数百万个 UpdateOne 语句,因为我有数百万个文档每天都会更新,而且要更新的数组比这个简单示例中的数组大得多。我也不太喜欢。
请注意,一个相关的问题是:第二个选项是否会使我的服务器过载,或者它是否不会占用比第一个选项更多的资源?第一个选项将意味着使用 bulkwrite ,比如 300'000 个 updateOne 语句,每个修改一个 365 长数组,而第二个选项意味着 300'000*364 个 updateOne 语句,每个修改一个数组元素。
我希望能够做类似的事情:
UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.1-end': [1 2 5.01 2 4 0 87 1 0.2 2 9]}})
即指定数组位置的范围,以替换为提供的数组。到目前为止,我找不到如何做到这一点。这将导致包含 300'000 个 updateOne 语句的批量写入,每个语句都准确地替换了需要替换的 364 个值。
注意:在这个例子中它取代了"all except the first value",但它也可能是"all except the last value"。可能还有 "replace elements at positions 4 to 9 by this array of length 6"。 我正在 python.
中编写代码您可以使用聚合管道并将其用于更新:
db.collection.updateOne(
{'year': 2020, 'location_id': 1},
[{
$set: {
values: {
$concatArrays: [
[{ $arrayElemAt: ["$values", 0] }],
[1, 2, 5.1, 2, 4, 0, 87, 1, 0.2, 2, 9]
]
}
}
}]
)
对于像"replace elements at positions 4 to 9 by this array of length 6"这样的操作你也可以使用$slice
也是运算符$range may help, see