MongoDB 4.2将聚合管道更新与阵列过滤器相结合

MongoDB 4.2将聚合管道更新与阵列过滤器相结合,mongodb,Mongodb,我看到MongoDB 4.2引入了聚合管道更新,它允许您基于文档中的其他字段设置文档字段 考虑到下列文件: { ean: "12345", orderedQty: 2, fulfilledQty: 1, "status": "pending" } 我可以使用以下命令将fulfilledQty增加1,如果orderedQty与fulfilledQty匹配,则相应地设置状态: db.collection.findOneAndUpdate({}, [ {

我看到MongoDB 4.2引入了聚合管道更新,它允许您基于文档中的其他字段设置文档字段

考虑到下列文件:

{
    ean: "12345",
    orderedQty: 2,
    fulfilledQty: 1,
    "status": "pending"
}
我可以使用以下命令将fulfilledQty增加1,如果orderedQty与fulfilledQty匹配,则相应地设置状态:

db.collection.findOneAndUpdate({}, [
  {
    "$set": {
        "orderedQty": {
            "$add": [ "$fulfilledQty", 1 ]
        }
    },  
    "$set": {
      "status": {
        "$cond": {
          "if": { "$eq": ["$orderedQty", "$fulfilledQty"] },
          "then": "fulfilled",
          "else": "pending"
        }
      }
    }
  }
])
我的问题是:如何在数组上执行此操作。假设我有这样一份文件:

_id: "test",
items: [
    {ean: "12345", orderedQty: 2, fulfilledQty: 1, "status": "pending"},
    {ean: "67891", orderedQty: 1, fulfilledQty: 1, "status": "fulfilled"}
]
假设我有参数ean=12345,并且增加值1。如何将EAN 12345作为特定数组项的目标,将fulfilledQty增加1并设置状态?我只想让status字段和fulfilledQty字段有机会,而让items数组的其余部分保持原样。因此,预期结果将是:

_id: "test",
items: [
    {ean: "12345", orderedQty: 2, fulfilledQty: 2, "status": "fulfilled"},
    {ean: "67891", orderedQty: 1, fulfilledQty: 1, "status": "fulfilled"}
]

我发现以下工作流程(仅适用于mongodb 4.2+),但它令人惊讶地冗长

假设有两个变量,一个项目标识符(称为
ean
)和一个发货数量(称为
fulfilledQty


我使用了switch语句,因为在我的用例中我有多个不同的ean。缺点是我必须使用$map操作,所以它总是迭代整个items数组。

我总是尝试创建目标更新,避免替换整个数组。如果从RDBMS的角度考虑,子文档的数组将有效地充当外部表关系。在这两种情况下(文档数据库与RDBMS),您必须有一种方法来唯一标识您希望更新的数据。在本例中,“ean”字段是键值吗?它在其他项目的数组中是唯一的吗?如果没有,则可能需要考虑数组项位置索引或标识另一个键。这感觉像是一个订单输入系统。大多数都有一个行项目编号可供输入。是的,ean在此处充当键。我知道如何使用“经典”数组更新操作符,但不知道如何使用4.2中引入的新聚合管道更新(或者即使可以使用聚合管道更新)
collection.update({}, [
  {
    $set: {
      items: {
        $map: {
          input: "$items",
          as: "item",
          in: {
            $mergeObjects: [
              "$$item",
              {
                fulfilledQty: {
                  $switch: {
                    branches: [
                      {
                        case: {
                          $eq: ["$$item.ean", ean]
                        },
                        then: {
                          $toInt: {
                            $add: ["$$item.fulfilledQty", fulfilledQty]
                          }
                        }
                      }
                    ],
                    default: "$$item.fulfilledQty"
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $set: {
      items: {
        $map: {
          input: "$items",
          as: "item",
          in: {
            $mergeObjects: [
              "$$item",
              {
                status: {
                  $cond: {
                    if: {
                      $eq: ["$$item.orderedQty", "$$item.fulfilledQty"]
                    },
                    then: "fulfilled",
                    else: "$$item.status"
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
]);