首页 > 解决方案 > 使用 $push 对数组进行多次更新

问题描述

考虑以下文档框架

{
  _id: "615749dce3438547adfff9bc",
  items: [
    {
      type: "shirt",
      color: "red",
      sizes: [
        {
          label: "medium",
          stock: 10,
          price: 20,
        },
        {
          label: "large",
          stock: 30,
          price: 40,
        }
      ]
    },
    {
      type: "shirt",
      color: "green",
      sizes: [
        {
          label: "small",
          stock: 5,
          price: 3,
        },
        {
          label: "medium",
          stock: 5,
          price: 3,
        },
      ]
    }
  ]
}

当一个新项目进来时,我想插入一个新文档到items,除非一个项目与新项目相同typecolor在这种情况下,我只想合并sizes到现有itemsizes.

sizes不必是唯一的

我尝试使用$pushwithupsert: truearrayFilters显然$push忽略了arrayFilters.

nodemongodb包。

标签: node.jsmongodb

解决方案


查询1

  • 过滤以查看是否存在
  • 如果存在要更新的地图,则在最后添加

*2 数组读取,但仍比 query2 快

测试代码在这里

db.collection.update({},
[
  {
    "$set": {
      "newitem": {
        "type": "shirt",
        "color": "red",
        "sizes": [
          {
            "label": "medium"
          }
        ]
      }
    }
  },
  {
    "$set": {
      "found": {
        "$ne": [
          {
            "$filter": {
              "input": "$items",
              "cond": {
                "$and": [
                  {
                    "$eq": [
                      "$$this.type",
                      "$newitem.type"
                    ]
                  },
                  {
                    "$eq": [
                      "$$this.color",
                      "$newitem.color"
                    ]
                  }
                ]
              }
            }
          },
          []
        ]
      }
    }
  },
  {
    "$set": {
      "items": {
        "$cond": [
          {
            "$not": [
              "$found"
            ]
          },
          {
            "$concatArrays": [
              "$items",
              [
                "$newitem"
              ]
            ]
          },
          {
            "$map": {
              "input": "$items",
              "in": {
                "$cond": [
                  {
                    "$and": [
                      {
                        "$eq": [
                          "$$this.type",
                          "$newitem.type"
                        ]
                      },
                      {
                        "$eq": [
                          "$$this.color",
                          "$newitem.color"
                        ]
                      }
                    ]
                  },
                  {
                    "$mergeObjects": [
                      "$$this",
                      {
                        "sizes": {
                          "$concatArrays": [
                            "$$this.sizes",
                            "$newitem.sizes"
                          ]
                        }
                      }
                    ]
                  },
                  "$$this"
                ]
              }
            }
          }
        ]
      }
    }
  },
  {
    "$unset": [
      "found",
      "newitem"
    ]
  }
])

Query2
(替代解决方案)

  • 减少并进行更新
  • 如果找到保持更新,否则在最后添加

*1 数组读取(但 concat 很慢,对于大数组,>500 个成员,如果您有大数组,请使用 query1)

*这是正常的方法,如果我们有一种快速的方法可以在数组末尾添加,但我们没有,所以 Query1 更快

测试代码在这里

db.collection.update({},
[
  {
    "$set": {
      "newitem": {
        "type": "shirt",
        "color": "red",
        "sizes": [
          {
            "label": "medium"
          }
        ]
      }
    }
  },
  {
    "$set": {
      "items-found": {
        "$reduce": {
          "input": "$items",
          "initialValue": {
            "items": [],
            "found": null
          },
          "in": {
            "$cond": [
              {
                "$and": [
                  {
                    "$eq": [
                      "$$value.found",
                      null
                    ]
                  },
                  {
                    "$eq": [
                      "$$this.type",
                      "$newitem.type"
                    ]
                  },
                  {
                    "$eq": [
                      "$$this.color",
                      "$newitem.color"
                    ]
                  }
                ]
              },
              {
                "items": {
                  "$concatArrays": [
                    "$$value.items",
                    [
                      {
                        "$mergeObjects": [
                          "$$this",
                          {
                            "sizes": {
                              "$concatArrays": [
                                "$$this.sizes",
                                "$newitem.sizes"
                              ]
                            }
                          }
                        ]
                      }
                    ]
                  ]
                },
                "found": true
              },
              {
                "items": {
                  "$concatArrays": [
                    "$$value.items",
                    [
                      "$$this"
                    ]
                  ]
                },
                "found": "$$value.found"
              }
            ]
          }
        }
      }
    }
  },
  {
    "$set": {
      "items": {
        "$cond": [
          "$items-found.found",
          "$items-found.items",
          {
            "$concatArrays": [
              "$items-found.items",
              [
                "$newitem"
              ]
            ]
          }
        ]
      }
    }
  },
  {
    "$unset": [
      "items-found",
      "newitem"
    ]
  }
])

推荐阅读