【问题标题】:Mongodb findoneandupdate with aggregation pipelineMongodb findoneandupdate 与聚合管道
【发布时间】: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 条件(第一个选项已注释),它可以正常工作。但如果我添加条件则不起作用。任何帮助,将不胜感激。谢谢

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregate-functions


    【解决方案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。 (与这个问题的上下文无关)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-24
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    相关资源
    最近更新 更多