【问题标题】:Mongodb compare two fields with matched fields value aggregateMongodb比较两个字段与匹配字段值聚合
【发布时间】:2019-01-02 12:46:41
【问题描述】:

我的查询有问题,我传递的参数是凭证Id 和userId,我需要检查该用户是否超过limitedQuantityPerUser。如果是,请排除此优惠券。但是我在比较匹配字段时遇到问题,例如如果凭证 ID 是 'aaa',请检查 quantityBrought > limitedQuantityPerUser。

我试过了

vouchers.find({
         'status': {
          $in: ['OP', 'WG', 'LO', 'SO']
        },
        'details.userReachedLimitedQuantity': {
          $ne: userId
        },
      }, fields, {
        sort: {
          'order': 1
        }
      }

但这会给我列表中 userId 不相等的所有结果。不完全是我需要的。使用聚合解决更好吗?

示例资源 JSON 文件

[{
        "_id": "111",
        "details": {
            "limitedQuantityPerUser": "3",
            "userReachedLimitedQuantity": [{
                    "userId": "aaa",
                    "quantityBrought": "2"
                },
                {
                    "userId": "bbb",
                    "quantityBrought": "1"
                },
                {
                    "userId": "ccc",
                    "quantityBrought": "3"
                }
            ],
            "status": "OP"
        }
    },
    {
        "_id": "222",
        "details": {
            "limitedQuantityPerUser": "2",
            "userReachedLimitedQuantity": [{
                    "userId": "eee",
                    "quantityBrought": "2"
                },
                {
                    "userId": "bbb",
                    "quantityBrought": "1"
                },
                {
                    "userId": "vvv",
                    "quantityBrought": "2"
                }
            ],
            "status": "OP"
        }
    }
]

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    您可以使用以下聚合来检查指定的userId 是否超出了定义的限制。

    db.vouchers.aggregate([
        {
            $match: {
                $expr: {
                    $allElementsTrue: {
                        $map: {
                            input: "$details.userReachedLimitedQuantity",
                            as: "user",
                            in: {
                                $or: [
                                    { $ne: [ "$$user.userId", userId ] },
                                    { $lte: [ "$$user.quantityBrought", "$details.limitedQuantityPerUser"  ] }
                                ]
                            }
                        }
                    }
                }
            }
        }
    ])
    

    $allElementsTrue 将一个布尔值数组作为参数。您可以使用$map 将您的userReachedLimitedQuantity 转换为检查userIdquantityBrought 字段的布尔值。

    因此,如果任何元素是false,则表示该用户的quantityBrought 大于limitedQuantityPerUser

    【讨论】:

    • 您好,感谢您的回答。尝试使用它时出现此错误 MongoError: $allElementsTrue's argument must be an array, but is null, 我试图在 { $map } 之间添加括号 [] 但仍然出现相同的错误
    • 您好,您知道如何仅投影匹配的“用户 ID”及其“数量”。因为 userReachedLimitedQuantity 可能会随着时间越来越大
    • 我设法通过使用双 [ [ ] ] 包装 { $map} 内容让您的代码正常工作。
    • 看起来添加双括号也不起作用,因为在文档中 [ [ false ] ], "isAllTrue" : true。对我来说,allElementsTrue 与 $map 配合得很好
    • @ThomasKim 我已经在您粘贴的那些文档上测试了我的解决方案,我猜您还有其他一些具有不同架构的文档,这就是为什么您得到这个 null,任何机会都可以在$match 上方申请之前将它们过滤掉?
    【解决方案2】:

    没有一个完美的答案,但是我在mongod查询的结果中做了过滤

    // Only take matched userId's quantityPurchased
    const newResult = result.filter(val => {
      if (!val.details.userReachedLimitedQuantity) {
        return val;
      }
      val.details.userReachedLimitedQuantity= val.details.userReachedLimitedQuantity.filter((o) => {
        return (String(o.userId) == userId)
      });
      if (val.details.userReachedLimitedQuantity[0].quantityBrou < val.details.limitedQuantityPerUser) {
        return val;
      } else {
        return false;
      }
    

    【讨论】:

      猜你喜欢
      • 2020-12-10
      • 2021-12-11
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      相关资源
      最近更新 更多