mongoose updateOne 功能:如果 $pull 不起作用则不更新

Posted

技术标签:

【中文标题】mongoose updateOne 功能:如果 $pull 不起作用则不更新【英文标题】:mongoose updateOne function: don't update if $pull didn't work 【发布时间】: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 字段,它对于特定的父文档来说是唯一的。 它工作得很好。感谢您的帮助 【参考方案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 在一个简化的示例中添加

以上是关于mongoose updateOne 功能:如果 $pull 不起作用则不更新的主要内容,如果未能解决你的问题,请参考以下文章

updateOne $ set not working - Mongoose

TypeScript 中的 Mongoose post hook 类型错误

UpdateOne MongoDB 使用来自另一个字段的值进行推送

使用 InsertOne/UpdateOne 在 DB 中添加值 - 如果找到以前的值;返回 NaN 而不是实际数字

mongoose更新前修改数据库

Mongoose findOneAndUpdate - 使用另一个字段更新一个字段[重复]