0

假设我有一系列商店:

[
  {
    "_id": 0,
    "items": [
      {"_id": 3, "price": 10}
    ]
  },
  {
    "_id": 1,
    "items": []
  },
  {
    "_id": 2
  }
]

我想将price商店中的商品 3 更新为 30,如果该商店中不存在商品,则在商店中插入新商品和/或在必要时插入新商店:

  • shop 0:简单地更新商品
  • 商店 1:附加{"_id": 3, "price": 30}到商店 1items
  • shop 2:将shop 2设置items[{"_id": 3, "price": 30}]
  • shop 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)

这有点像$with upsert,但文档明确指出upsert不能与它一起使用:

不要将位置运算符$与 upsert 操作一起使用,因为插入操作会$在插入的文档中将 用作字段名称。

$[<identifier>]也不起作用:

如果 upsert 操作不包括完全相等匹配并且没有找到要更新的匹配文档,则 upsert 操作将出错。

有没有办法做到这一点而不必多次访问数据库?


我尝试过的事情:

// 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}
)
4

1 回答 1

0

正如D. SM所说,您可以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
    }
  }
])
于 2020-08-31T09:30:24.157 回答