$ 带 upsert 的位置更新运算符
$ positional update operator with upsert
假设我有一系列商店:
[
{
"_id": 0,
"items": [
{"_id": 3, "price": 10}
]
},
{
"_id": 1,
"items": []
},
{
"_id": 2
}
]
我想将商店中商品 3 的 price
更新为 30,如果该商店中没有商品,则在商店中插入一个新商品 and/or 如有必要,插入一个新商店:
- shop 0: 简单更新商品
- 商店 1:将
{"_id": 3, "price": 30}
附加到商店 1 的 items
- 店铺 2:将店铺 2 的
items
设置为 [{"_id": 3, "price": 30}]
- 店铺3:插入文件
{"_id": 3, "items": [{"_id": 3, "price": 30}]}
换句话说,我想:
collection.updateOne({_id: <shopId>, 'items._id': 3}, {$set: {'items.$.price': 30}})
如果商品存在(商店 0)
collection.updateOne({_id: <shopId>}, {$push: {items: {_id: 3, price: 30}}}, {upsert: true})
如果没有(商店 1 到 3)
这有点像 $
和 upsert
,但是 the documentation 明确指出 upsert
不能与它一起使用:
Do not use the positional operator $
with upsert operations because inserts will use the $
as a field name in the inserted document.
$[<identifier>]
也不行:
If the upsert operation did not include an exact equality match and no matching documents were found to update, the upsert operation would error.
有没有办法不用多次访问数据库就可以做到这一点?
我尝试过的事情:
// Updating the path 'items' would create a conflict at 'items'
collection.updateOne(
{_id: 0, 'items._id': 3},
{$set: {'items.$.price': 30}, $setOnInsert: {items: []}}
)
// $[<identifier>] with upsert doesn't work
// The path 'items' must exist in the document in order to apply array updates.
collection.updateOne(
{_id: 2},
{$set: {'items.$[item].price': 30}},
{arrayFilters: [{'item._id': 3}], upsert: true}
)
// Updating the path 'items' would create a conflict at 'items'
collection.updateOne(
{_id: 0},
{$set: {'items.$[item].price': 30}, $setOnInsert: {items: []}},
{arrayFilters: [{'item._id': 3}], upsert: true}
)
作为D. SM said, you can use bulkWrite
一次做多个操作:
const shopId = 0
collection.bulkWrite([
// Remove any existing item
{
updateOne: {
filter: {_id: shopId},
update: {$pull: {items: {_id: 3}}}
}
},
// Add the item with the updated price to the shop
{
updateOne: {
filter: {_id: shopId},
update: {
$push: {items: {_id: 3, price: 30}}
},
upsert: true
}
}
])
假设我有一系列商店:
[
{
"_id": 0,
"items": [
{"_id": 3, "price": 10}
]
},
{
"_id": 1,
"items": []
},
{
"_id": 2
}
]
我想将商店中商品 3 的 price
更新为 30,如果该商店中没有商品,则在商店中插入一个新商品 and/or 如有必要,插入一个新商店:
- shop 0: 简单更新商品
- 商店 1:将
{"_id": 3, "price": 30}
附加到商店 1 的items
- 店铺 2:将店铺 2 的
items
设置为[{"_id": 3, "price": 30}]
- 店铺3:插入文件
{"_id": 3, "items": [{"_id": 3, "price": 30}]}
换句话说,我想:
collection.updateOne({_id: <shopId>, 'items._id': 3}, {$set: {'items.$.price': 30}})
如果商品存在(商店 0)collection.updateOne({_id: <shopId>}, {$push: {items: {_id: 3, price: 30}}}, {upsert: true})
如果没有(商店 1 到 3)
这有点像 $
和 upsert
,但是 the documentation 明确指出 upsert
不能与它一起使用:
Do not use the positional operator
$
with upsert operations because inserts will use the$
as a field name in the inserted document.
$[<identifier>]
也不行:
If the upsert operation did not include an exact equality match and no matching documents were found to update, the upsert operation would error.
有没有办法不用多次访问数据库就可以做到这一点?
我尝试过的事情:
// Updating the path 'items' would create a conflict at 'items'
collection.updateOne(
{_id: 0, 'items._id': 3},
{$set: {'items.$.price': 30}, $setOnInsert: {items: []}}
)
// $[<identifier>] with upsert doesn't work
// The path 'items' must exist in the document in order to apply array updates.
collection.updateOne(
{_id: 2},
{$set: {'items.$[item].price': 30}},
{arrayFilters: [{'item._id': 3}], upsert: true}
)
// Updating the path 'items' would create a conflict at 'items'
collection.updateOne(
{_id: 0},
{$set: {'items.$[item].price': 30}, $setOnInsert: {items: []}},
{arrayFilters: [{'item._id': 3}], upsert: true}
)
作为D. SM said, you can use bulkWrite
一次做多个操作:
const shopId = 0
collection.bulkWrite([
// Remove any existing item
{
updateOne: {
filter: {_id: shopId},
update: {$pull: {items: {_id: 3}}}
}
},
// Add the item with the updated price to the shop
{
updateOne: {
filter: {_id: shopId},
update: {
$push: {items: {_id: 3, price: 30}}
},
upsert: true
}
}
])