【问题标题】:mongoose updateOne function: don't update if $pull didn't workmongoose updateOne 功能:如果 $pull 不起作用则不更新
【发布时间】:2020-12-01 02:14:06
【问题描述】:

我正在使用这样的updateOne 方法:

Photo.updateOne(
    {
        "_id": photoId
    },
    {
        "$pull": {
            comments: {
                _id: ObjectID(commentId),
                "user.id": user.id
            }
        },
        "$inc": { "commentCount": -1 },
    },
)

Photo 包含 cmets 作为数组和 commentCount 作为数字的模型。当我运行代码时,它正在工作,但如果照片没有评论(我试图拉)它仍然将commentCount 增加-1。我想要的是,如果代码没有在照片 cmets 中提取任何评论,也不要更新 commentCount。如何将此规则添加到我的代码中?

感谢您的帮助。

【问题讨论】:

  • 我已经更新了我的答案,在查询部分添加了$elemMatch,以确保 cmets 上的两个字段相等,然后进入更新部分,在极少数情况下会发生这种情况,否则我的旧条件也将起作用,因为您正在更新单个文档并几乎使用 _id 字段,它对于特定的父文档来说是唯一的。
  • 它工作得很好。感谢您的帮助

标签: mongodb mongoose mongodb-query mongoose-schema


【解决方案1】:

您也可以在查询部分同时添加comments._idcomments.use.id 条件,如果评论不可用则跳过更新和拉取部分。

Photo.updateOne(
    { 
        _id: photoId,
        comments: {
            $elemMatch: {
                _id: ObjectID(commentId),
                "user.id": user.id
            }
        }
    },
    {
        "$pull": {
            comments: {
                _id: ObjectID(commentId),
                "user.id": user.id
            }
        },
        "$inc": { "commentCount": -1 }
    }
)

【讨论】:

  • 您需要 elemMatch 以确保 comments._idcomments.user.id 满足相同的评论。
  • @Joe 感谢您的建议,我已经在没有$elemMatch它的情况下进行了测试,它工作得很好。如果您说要在查询部分中使用,那么默认情况下更新是使用. 点提供数组匹配,则无需使用该运算符,如果您说要在更新(拉)部分中使用,那么它将不起作用,因为$elemMatch 只是查询和投影运算符。
  • 我的意思是,如果 cmets 数组中的一个元素与"comments._id": ObjectID(commentId) 匹配,而另一个元素与"comments.user.id": user.id 匹配,它将满足您在此处显示的查询部分,但$pull 不会在$inc 修改计数时删除任何内容。在查询部分使用$elemMatch 可以防止这种情况发生。
【解决方案2】:

Mongo 中不存在这样的功能,如果您使用 Mongo v4.2+,您可以使用pipelined update,顾名思义,这使您能够在更新中使用管道,因此允许我们根据之前的结果来获得条件。

Photo.updateOne(
    { "_id": photoId },
    [
        {
            $set: {
              comments: {
                  $filter: {
                     input: "$comments",
                     as: "comment",
                     cond: {
                         $and: [
                           {$ne: ["$$comment._id", ObjectID(commentId)]},
                           {$ne: ["$$comment.user.id", user.id]} //really necessary?
                          ]
                     }
                  }
               }
            }
        },
        {
            $set: {
                commentCount: {$size: "$comments"}
            }
        }
    ]
)

对于较小的版本,您必须将其拆分为 2 个调用。没办法。

------------- 编辑 ----------------

您可以使用$elemMatch 更新查询以查找文档,如果找不到,则表示该评论属于其他人,在这种情况下您可以抛出错误。

Photo.updateOne(
    { 
        _id: photoId,
        comments: {
           $elemMatch: {
               _id: objectID(commentId),
               "user.id": user.id
           }
        }
    },
    {
        "$pull": {
            comments: {
                _id: ObjectID(commentId),
                "user.id": user.id
            }
        },
        "$inc": { "commentCount": -1 }
    }
)

【讨论】:

  • 感谢您的回答,但效果不佳。我正在尝试这样做,因为如果用户尝试删除其他人的评论,我想返回一条错误消息。在您的代码中,如果用户尝试删除其他用户的评论,这将起作用,因为条件错误。假设我们有 2 个不同的评论,例如 {userId:1,commentId:1}, {userId:2,commentId:2} 如果一个 id 值等于 3 的用户尝试删除 commentId=1 这将成功,因为您的代码检查条件 commentId != 1 && userId != 3,这将只返回第二条评论。
  • 您可以检查modifiedCount 以查看文档是否已更改,然后抛出错误。既然我了解了您的需求,请使用$elemMatch 在一个简化的示例中添加
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多