使用聚合管道的Mongodb findoneandupdate

5

我在 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字段。 我已经使用了以下两个选项

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条件的话,代码可以正常工作(第一个选项已被注释掉)。但是如果我添加了这个条件,代码就不能正常工作。任何帮助将不胜感激。谢谢。

2个回答

3

尝试使用$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的答案看起来更优雅。谢谢。 - Ananth Vivek

1
你需要使用 $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 }
)

它的运行非常顺畅...我想将条件更改为名称,即仅在名称字段的值为“test”时求和。我将条件更改为cond: {$eq:['$$this.Name','test']},但它不起作用。 - Ananth Vivek
@AnanthVivek 请再检查一下,我已经更新了我的答案。 - Valijon
谢谢,它可以工作了。请将$gte更改为$eq。(中间的内容与此问题的上下文无关) - Ananth Vivek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接