MongoDB 4.2将聚合管道更新与数组过滤器结合在一起

时间:2019-12-05 14:24:59

标签: mongodb

我看到MongoDB 4.2引入了聚合管道更新,这使您可以基于文档中的其他字段设置文档字段。

考虑以下文件

{
    ean: "12345",
    orderedQty: 2,
    fulfilledQty: 1,
    "status": "pending"
}

我可以使用以下命令将满额数量增加1,如果orderedQty与满额数量匹配,则相应地设置状态:

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定位特定的数组项,如何将completedQty增加1并设置状态?我只想让status字段和completedQty字段碰碰运气,而其余的items数组保持原样。因此预期结果将是:

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

1 个答案:

答案 0 :(得分:0)

我发现了以下工作流程(仅适用于mongodb 4.2+),但是它非常冗长……

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

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"
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
]);

我使用了switch语句,因为在我的用例中,我有多个不同的EAN。缺点是我必须使用$ map操作,因此它总是遍历整个items数组。