【问题标题】:Remove Embedded Documents in an Array in MongoDB with mongoose (updateOne - $pull) not work使用 mongoose (updateOne - $pull) 删除 MongoDB 中数组中的嵌入式文档不起作用
【发布时间】:2022-04-22 16:09:26
【问题描述】:

我在 NodeJs 中有一个带有 MongoDB (Mongoose) 的应用程序。

在一个集合中,我有这种类型的文档,按周定义:

{
"_id":
{"$oid":"617f3f51f883fab2de3e7260"},
"endDate":{"$date":"2021-11-07T23:59:59.000Z"},
"startDate":{"$date":"2021-11-01T00:00:00.000Z"},
"wastes":[
{"timestamp":{"$date":"2021-11-01T01:00:58.000Z"},"duration":780},
{"timestamp":{"$date":"2021-11-01T01:00:58.000Z"},"duration":1140},
{"timestamp":{"$date":"2021-11-01T03:00:58.000Z"},"duration":540},
{"timestamp":{"$date":"2021-11-01T07:00:58.000Z"},"duration":540},
{"timestamp":{"$date":"2021-11-01T09:00:58.000Z"},"duration":960},
{"timestamp":{"$date":"2021-11-01T09:00:58.000Z"},"duration":1140},
{"timestamp":{"$date":"2021-11-01T15:00:58.000Z"},"duration":180},
{"timestamp":{"$date":"2021-11-01T15:00:58.000Z"},"duration":540}
...
]}

我有一个查找具有相同时间戳的废物的函数,例如"2021-11-01T01:00:58.000Z",给出了该时间戳的最长持续时间。

我想删除所有带有该时间戳的条目:

{"timestamp":{"$date":"2021-11-01T01:00:58.000Z"},"duration":780},
{"timestamp":{"$date":"2021-11-01T01:00:58.000Z"},"duration":1140}

并且只插入持续时间最长的那个:

{"timestamp":{"$date":"2021-11-01T01:00:58.000Z"},"duration":1140}

我正在使用带有 $pull 和 $push 的 updateOne,但它不起作用。

let query = {
        startDate: new Date(startDayWeek),
      };

let deleteProjection = {
        $pull: {
          wastes: { timestamp: new Date(timestampDeleteInsertion) },
        },
      };

let insertProjection = {
        $push: { wastes: insertRegisterForTimestamp },
      };

//Delete
await coleccion.updateOne(query, deleteProjection);

//Insertion
await coleccion.updateOne(query, insertProjection);

我也试过{upsert: false}, {multi: true}

如果我在 MongoDB Compass shell 中使用相同的命令,它可以正常工作:

//Delete
db.coleccion.updateOne({startDate: ISODate('2021-11-01T00:00:00')}, {$pull: {'wastes': {timestamp: ISODate('2021-11-01T01:00:58.000Z')}}})

//Insertion
db.coleccion.updateOne({startDate: ISODate('2021-11-01T00:00:00')}, {$push: {'wastes': {'timestamp':ISODate('2021-11-01T01:00:58.000Z'), 'duration': 1140}}})

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    您可以使用Updates with Aggregation Pipeline 实现预期行为

    聚合将包括 3 个步骤:

    1. 使用$reduce找出最大持续时间;将结果存储到字段中
    2. $filter wastes 数组,只保留不等于所选时间戳或持续时间不是最大持续时间的元素
    3. $unset 步骤 1 中创建的辅助字段
    db.collection.update({},
    [
      {
        $addFields: {
          maxDuration: {
            "$reduce": {
              "input": "$wastes",
              "initialValue": null,
              "in": {
                "$cond": {
                  "if": {
                    $and: [
                      {
                        $eq: [
                          "$$this.timestamp",
                          {
                            "$date": "2021-11-01T01:00:58.000Z"
                          }
                        ]
                      },
                      {
                        $gt: [
                          "$$this.duration",
                          "$$value"
                        ]
                      }
                    ]
                  },
                  "then": "$$this.duration",
                  "else": "$$value"
                }
              }
            }
          }
        }
      },
      {
        $set: {
          wastes: {
            $filter: {
              input: "$wastes",
              as: "w",
              cond: {
                $or: [
                  {
                    $ne: [
                      "$$w.timestamp",
                      {
                        "$date": "2021-11-01T01:00:58.000Z"
                      }
                    ]
                  },
                  {
                    $eq: [
                      "$$w.duration",
                      "$maxDuration"
                    ]
                  }
                ]
              }
            }
          }
        }
      },
      {
        "$unset": "maxDuration"
      }
    ])
    

    这里是Mongo playground 供您参考。

    【讨论】:

    • "$unset": ["maxDuration"] 问题:“管道中的 $unset 无效,必须是字符串数组”
    • 您是否在 maxDuration 周围使用方括号?在我们这里,我们不需要它。
    【解决方案2】:

    我对 updateOne 和 pull 命令有同样的问题,如果将 updateOne 与 push 一起使用,它可以工作。 在 mongo shell 或 compass 中,两种情况(推/拉)都有效,但使用 mongoose,它会找到标准但不更新/修改。

    Result
    
    {
        "acknowledged" : true,
        "matchedCount" : 1.0,
        "modifiedCount" : 0.0
    }
    

    【讨论】:

    • 这并不能真正回答问题。如果您有其他问题,可以点击 进行提问。要在此问题有新答案时收到通知,您可以follow this question。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review
    猜你喜欢
    • 2022-01-08
    • 2013-02-13
    • 2021-03-03
    • 1970-01-01
    • 2021-03-30
    • 2021-09-12
    • 2019-07-16
    • 2016-02-09
    • 2013-03-24
    相关资源
    最近更新 更多