Mongodb findoneandupdate 与聚合管道

Posted

技术标签:

【中文标题】Mongodb findoneandupdate 与聚合管道【英文标题】:Mongodb findoneandupdate with aggregation pipeline 【发布时间】:2020-09-20 15:01:58 【问题描述】:

我在 MongoDB 中有这样的数据

    "_id":"$oid":"5ec4ed0b94996124187b95ce",
           "cid":"245345323",
     "dtl":[
          "_id":"$oid":"5ed5ab655df7930ec424be1e",
              "sid":"test",
              "amt":"$numberInt":"48",
              "Name":"test",
          "_id":"$oid":"5ed5ac9f79a75423d4bc0270",
             "sid":"s",
             "amt":"$numberInt":"14",
             "Name":"sfds",
          "_id":"$oid":"5ed5ace7d204ab144863ed7a",
             "sid":"wesad",
             "amt":"$numberInt":"6",
             "Name":"2sdad"
          ,
        "updated":"$date":"$numberLong":"1589964043787",
        "__v":"$numberInt":"6",
       "TotalAmt":"$numberInt":"68"

仅当数组中的 amt 字段的值大于 10 时,我才需要更新 TotalAmt 字段。我使用了以下 2 个选项

PM.findOneAndUpdate(
      
        _id: MongoId,
      ,
      [
        
          $set: 
            //TotalAmt:  $sum: '$dtl.amt' ,
            /*TotalAmt: 
              $cond: 
                if:  $gte: ['$dtl.amt', 10] ,
                then:  $sum: '$dtl.amt' ,
                else: 0,
              ,
            ,*/
          ,
        ,
      ],
       new: true 
    )

如果没有 amt > 10 条件(第一个选项已注释),它可以正常工作。但如果我添加条件则不起作用。任何帮助,将不胜感激。谢谢

【问题讨论】:

【参考方案1】:

尝试使用$map改变$sum的输入结构:


PM.findOneAndUpdate(
    
        _id: MongoId,
    ,
    [
        
            $set: 
                TotalAmt: 
                    $cond: 
                        if: $gte: ['$dtl.amt', 10],
                        then: 
                            $sum: 
                                $map: 
                                   input: '$dtl',
                                   as: "item",
                                   in: "$$item.amt" 
                                
                            ,
                        ,     
                        else: 0, // 0 or "$TotalAmt" ? 
                    ,
                ,
            ,
        ,
    ],
    new: true
)

【讨论】:

它有效,但 Valijon 的回答看起来很优雅。谢谢【参考方案2】:

你需要使用$filter操作符:

PM.findOneAndUpdate(
  
    _id: MongoId,
  ,
  [
    
      $set: 
        TotalAmt:  
          $sum: 
            $filter: 
              input: '$dtl.amt',
              cond:  $gte: ['$$this', 10] 
            
          
        
      
    
  ]
   new: true 
)

---输出---


    "_id" : ObjectId("5ec4ed0b94996124187b95ce"),
    "cid" : "245345323",
    "dtl" : [ 
        
            "_id" : ObjectId("5ed5ab655df7930ec424be1e"),
            "sid" : "test",
            "amt" : 48,
            "Name" : "test"
        , 
        
            "_id" : ObjectId("5ed5ac9f79a75423d4bc0270"),
            "sid" : "s",
            "amt" : 14,
            "Name" : "sfds"
        , 
        
            "_id" : ObjectId("5ed5ace7d204ab144863ed7a"),
            "sid" : "wesad",
            "amt" : 6,
            "Name" : "2sdad"
        
    ],
    "updated" : ISODate("2020-05-20T08:40:43.787Z"),
    "__v" : 6,
    "TotalAmt" : 62

编辑:如果要按其他字段过滤,我们需要添加额外的$map 运算符。

PM.findOneAndUpdate(
  
    _id: MongoId,
  ,
  [
    
      $set: 
        TotalAmt:  
          $sum: 
            $map:
                input: 
                  $filter: 
                    input: '$dtl',
                    cond:  $eq: ['$$this.Name', 'test'] 
                  
                ,
                in:"$$this.amt"
            
          
        
      
    
  ],
   new: true 
)

【讨论】:

它就像一个魅力......我想将条件更改为名称,即只有在名称字段的值为“测试”时才求和。我改变了这样的条件 cond: $eq: ['$$this.Name', 'test'] 但它不起作用。 @AnanthVivek 再看一遍,我已经更新了答案 谢谢它有效。请将 $gte 更改为 $eq。 (与这个问题的上下文无关)

以上是关于Mongodb findoneandupdate 与聚合管道的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB - Mongoose 查询 findOneAndUpdate() 不更新/复制数据库

findOneAndUpdate 未在 MongoDb 中返回更新的文档 [重复]

findOneAndUpdate 未在 MongoDb 中返回更新的文档 [重复]

如何在 mongodb 的 findOneAndUpdate 中使用对象作为过滤器

MongoDB findOneAndUpdate 返回 null

MongoDB findOneAndUpdate 返回 null