如何在mongodb中只更新数组过滤器的一个匹配项

r6hnlfcb  于 2023-01-08  发布在  Go
关注(0)|答案(2)|浏览(188)

问题:

我只需要更新spots可用数组中一个id为"empty"的文档。我之前的查询是更新所有匹配的id为"empty"的子文档;这是不好的 * 下面的例子 *。所以我决定使用聚合,这样我就可以添加一个限制阶段,这样我就只能更新一个项目,但是我发现我不能用聚合来更新原始文档。**这就只剩下了使用数组过滤器的唯一选择,该过滤器只更新其匹配项中的一个/第一个。**这可能吗?我觉得必须有一种方法来只更新一个匹配的数组过滤器,如果没有,这肯定是应该添加的东西。

我的代码:

  • 此代码使用"空"更新每个对象 *
const client = await clientPromise;
            const db = client.db();
            // const query = db.collection('events').aggregate(agg);

            const query = await db.collection('events').updateOne({
                _id: new ObjectId("6398c34ca67dbe3286452f23"),
                createdBy: new ObjectId("636c1778f1d09191074f9690"),
                "weights.weight": 12
            },
                {
                    $set: {
                        "weights.$.spotsAvailable.$[el2]": {
                            "name": "Wayne Wrestler",
                            "userId": new ObjectId("636c1778f1d09191074f9690")
                        }
                    }
                },
                {
                    arrayFilters: [{ "el2": { "userId": "empty" } }]
                })

示例文档:

事件:

{
  "_id": {
    "$oid": "6398c34ca67dbe3286452f23"
  },
  "name": "test",
  "createdBy": {
    "$oid": "636c1778f1d09191074f9690"
  },
  "description": "testing",
  "date": {
    "$date": {
      "$numberLong": "1645488000000"
    }
  },
  "location": {
    "type": "Point",
    "coordinates": [
      0,
      0
    ]
  },
  "weights": [
    {
      "spotsAvailable": [
        {
          "name": "empty",
          "userId": "empty"
        },
        {
          "name": "empty",
          "userId": "empty"
        },
        {
          "name": "empty",
          "userId": "empty"
        }
      ],
      "weight": 12
    },
    {
      "spotsAvailable": [
        {
// only one of these should've been updated, but both were
          "name": "Wayne Wrestler",
          "userId": {
            "$oid": "636c1778f1d09191074f9690"
          }
        },
        {
          "name": "Wayne Wrestler",
          "userId": {
            "$oid": "636c1778f1d09191074f9690"
          }
        }
      ],
      "weight": 15
    }
  ],
  "eventApplicants": [
    {
      "userId": {
        "$oid": "636c1778f1d09191074f9690"
      },
      "name": "Wayne Wrestler",
      "weight": 12
    }
  ]
}

用户:

{
  "_id": {
    "$oid": "636c1778f1d09191074f9690"
  },
  "name": "Wayne Wrestler",
  "email": "wakywayne80@gmail.com",
  "image": "https://lh3.googleusercontent.com/a/ALm5wu32gXjDIRxncjjQA9I4Yl-sjFH5EWsTlmvdM_0kiw=s96-c",
  "emailVerified": {
    "$date": {
      "$numberLong": "1670864727212"
    }
  },
  "createdEvents": [
    {
      "createdEventName": "test",
      "createdEventDate": {
        "$date": {
          "$numberLong": "1645488000000"
        }
      },
      "createdEventDescription": "testing",
      "createdEventWeights": [
        {
          "weight": "12",
          "filled": [
            false,
            false,
            false
          ]
        },
        {
          "weight": "15",
          "filled": [
            false,
            false
          ]
        }
      ],
      "createdEventId": {
        "$oid": "6398c34ca67dbe3286452f23"
      }
    }
  ],
  "userSignedUpEvents": [],
  "availableWeights": [
    1,
    123
  ],
  "signedUpEvents": [
    {
      "eventId": {
        "$oid": "636c722f67642c30dc5ffc30"
      },
      "eventName": "Utah",
      "eventDate": {
        "$date": {
          "$numberLong": "1667913330000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "636c722f67642c30dc5ffc30"
      },
      "eventName": "Utah",
      "eventDate": {
        "$date": {
          "$numberLong": "1667913330000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "637ec484ac2d675b30590b47"
      },
      "eventName": "Maybe?",
      "eventDate": {
        "$date": {
          "$numberLong": "1672272000000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "636c722f67642c30dc5ffc30"
      },
      "eventName": "Utah",
      "eventDate": {
        "$date": {
          "$numberLong": "1667913330000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "638d5274628db2a7bf61df49"
      },
      "eventName": "Eva's",
      "eventDate": {
        "$date": {
          "$numberLong": "1698019200000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "636c722f67642c30dc5ffc30"
      },
      "eventName": "Utah",
      "eventDate": {
        "$date": {
          "$numberLong": "1667913330000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "6398a922abb5c168ede595fb"
      },
      "eventName": "Nikko's event",
      "eventDate": {
        "$date": {
          "$numberLong": "1670976000000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "6398a922abb5c168ede595fb"
      },
      "eventName": "Nikko's event",
      "eventDate": {
        "$date": {
          "$numberLong": "1670976000000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "6398c34ca67dbe3286452f23"
      },
      "eventName": "test",
      "eventDate": {
        "$date": {
          "$numberLong": "1645488000000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "6398c34ca67dbe3286452f23"
      },
      "eventName": "test",
      "eventDate": {
        "$date": {
          "$numberLong": "1645488000000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "6398c34ca67dbe3286452f23"
      },
      "eventName": "test",
      "eventDate": {
        "$date": {
          "$numberLong": "1645488000000"
        }
      },
      "accepted": false
    },
    {
      "eventId": {
        "$oid": "6398c34ca67dbe3286452f23"
      },
      "eventName": "test",
      "eventDate": {
        "$date": {
          "$numberLong": "1645488000000"
        }
      },
      "accepted": false
    }
  ]
}

我试过:
1.插入不使用new ObjectId语法的变量
1.使用new ObjectId语法的插件变量
1.使用与从节点驱动程序的compass复制聚合代码时获得的硬编码值完全相同的值
所有这些方法要么不起作用,要么导致每个包含"空"的子文档都被填满

41ik7eoe

41ik7eoe1#

一个选项是使用管道更新:
由于这是一个双重嵌套数组,因此分内部和外部两步来完成比较容易
1.首先在weights数组中创建要替换的"外部"项,并将其命名为newItem。它是使用$reduce计算的,这允许我们在循环内部数组时对其进行操作。
1.将weights阵列上的相关项替换为我们的newItem使用$map替换为$cond

db.collection.update(
  {_id: ObjectId("6398c34ca67dbe3286452f23"), "weights.weight": 12},
  [
    {$set: {
      newItem: {$reduce: {
          input: {$getField: {
              input: {$first: {
                  $filter: {
                    input: "$weights",
                    as: "item",
                    cond: {$eq: ["$$item.weight", 12]}
                  }
              }},
              field: "spotsAvailable"
          }},
          initialValue: [],
          in: {$concatArrays: [
              "$$value",
              {$cond: [
                  {$and: [
                      {$eq: ["$$this.userId", "empty"]},
                      {$not: {$in: [ObjectId("636c1778f1d09191074f9690"), "$$value.userId"]}}
                  ]},
                  [{
                      name: "Wayne Wrestler",
                      userId: ObjectId("636c1778f1d09191074f9690")
                  }],
                  ["$$this"]
                ]}
            ]}
      }}
  }},
  {$set: {
      weights: {$map: {
          input: "$weights",
          in: {$cond: [
              {$eq: ["$$this.weight", 12]},
              {$mergeObjects: [
                  "$$this",
                  {spotsAvailable: "$newItem"}
              ]},
              "$$this"
          ]}
      }},
      newItem: "$$REMOVE"
  }}
])

了解它在playground example上的工作原理

watbbzwu

watbbzwu2#

可以先对weights进行$unwind处理,先用$reduce迭代weights.spotsAvailable数组,用复合对象存储结果,用标志表示是否更新,最后用结果$merge返回到原始文档。

db.collection.aggregate([
  {
    $match: {
      "_id": ObjectId("6398c34ca67dbe3286452f23"),
      createdBy: ObjectId("636c1778f1d09191074f9690"),
      "weights.weight": 12,
      "weights.spotsAvailable.userId": "empty"
    }
  },
  {
    "$unwind": "$weights"
  },
  {
    "$addFields": {
      "results": {
        "$reduce": {
          "input": "$weights.spotsAvailable",
          "initialValue": {
            result: [],
            updated: false
          },
          "in": {
            "$cond": {
              "if": {
                $and: [
                  {
                    $eq: [
                      false,
                      "$$value.updated"
                    ]
                  },
                  {
                    $eq: [
                      "empty",
                      "$$this.userId"
                    ]
                  }
                ]
              },
              "then": {
                result: {
                  "$concatArrays": [
                    "$$value.result",
                    [
                      {
                        "name": "Wayne Wrestler",
                        "userId": ObjectId("636c1778f1d09191074f9690")
                      }
                    ]
                  ]
                },
                updated: true
              },
              "else": {
                result: {
                  "$concatArrays": [
                    "$$value.result",
                    [
                      "$$this"
                    ]
                  ]
                },
                updated: "$$value.updated"
              }
            }
          }
        }
      }
    }
  },
  {
    $set: {
      "weights.spotsAvailable": "$results.result",
      "results": "$$REMOVE"
    }
  },
  {
    $group: {
      _id: "$_id",
      "name": {
        $first: "$name"
      },
      "createdBy": {
        $first: "$createdBy"
      },
      "description": {
        $first: "$description"
      },
      "date": {
        $first: "$date"
      },
      "location": {
        $first: "$location"
      },
      "weights": {
        $push: "$weights"
      },
      "eventApplicants": {
        $first: "$eventApplicants"
      }
    }
  },
  {
    "$merge": {
      "into": "collection",
      "on": "_id"
    }
  }
])

Mongo Playground

相关问题