【问题标题】:Compare embedded document to parent field with mongoDB使用 mongoDB 将嵌入文档与父字段进行比较
【发布时间】:2020-07-24 03:30:08
【问题描述】:

考虑以下集合,其中父文档有一个 amount 字段,其值为 100000,并且有一个嵌入的文档数组,其具有相同的字段 amount 和相同的值。

{
"_id" : ObjectId("5975ce5f05563b6303924914"),
"amount" : 100000,
"offers" : [ 
    {
        "amount": 100000
    }
]

}

是否有任何方法可以匹配所有具有至少一个嵌入文档offer 的对象与父对象的数量相同?

如果我例如查询这个,它工作得很好:

find({ offers: { $elemMatch: { loan_amount: 100000 } } })

但我不知道实际值 100000 在我尝试组装的实际查询中,我需要为父文档金额字段使用一个变量。像这样。

find({ offers: { $elemMatch: { loan_amount: "parent.loan_amount" } } })

感谢您的任何建议。我希望使用$eq$elemMatch 来执行此操作,并避免聚合,但也许这是不可能的。

谢谢!

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    标准查询无法“比较”文档中的值。这实际上是您使用 .aggregate()$redact 所做的事情:

    db.collection.aggregate([
      { "$redact": {
        "$cond": {
          "if": {
            "$gt": [
              { "$size": {
                "$filter": {
                  "input": "$offers",
                  "as": "o",
                  "cond": { "$eq": [ "$$o.amount", "$amount" ] }
                }
              }},
              0
            ]
          },
          "then": "$$KEEP",
          "else": "$$PRUNE"
        }
      }}
    ])
    

    这里我们使用$filter 将父文档中"amount" 的值与数组中的值进行比较。如果至少有一个“相等”,那么我们"$$KEEP" 文档,否则我们"$$PRUNE"

    在最新版本中,我们可以使用 $indexOfArray 缩短它。

    db.collection.aggregate([
      { "$redact": {
        "$cond": {
          "if": {
            "$ne": [
              { "$indexOfArray": [ "$offers.amount", "$amount" ] },
              -1
            ]
          },
          "then": "$$KEEP",
          "else": "$$PRUNE"
        }
      }}
    ])
    

    如果您实际上也只想要“匹配的数组元素”,那么您可以在投影中添加 $filter

    db.collection.aggregate([
      { "$redact": {
        "$cond": {
          "if": {
            "$gt": [
              { "$size": {
                "$filter": {
                  "input": "$offers",
                  "as": "o",
                  "cond": { "$eq": [ "$$o.amount", "$amount" ] }
                }
              }},
              0
            ]
          },
          "then": "$$KEEP",
          "else": "$$PRUNE"
        }
      }},
      { "$project": {
        "amount": 1,
        "offers": {
          "$filter": {
            "input": "$offers",
            "as": "o",
            "cond": { "$eq": [ "$$o.amount", "$amount" ] }
          }
        }
      }}
    ])
    

    但主要原则当然是“减少”返回的文档数量那些真正符合条件的文档作为“第一”优先级。否则,您只是在进行不必要的计算和工作,这些工作会耗费时间和资源,而您以后会丢弃结果。

    因此,首先要“过滤”,其次才是“重塑”。

    【讨论】:

    • 非常感谢,如果 offer 文档有自己的集合并引用其他文档会更容易吗?这种聚合似乎需要做很多工作,我的意思是性能方面,将报价文档放在它自己的集合中并引用其他文档 ID 是否更好?
    • @StefanKonno “性能明智”将内容放入另一个集合更糟糕。加入成本,而且非常昂贵。这就是为什么你“应该”首先使用 MongoDB。没有“简单”的方法可以将一个领域与另一个领域进行比较。任何方法都有成本,关系数据库也是如此。
    • 再次感谢,我会试一试。感谢您的努力,祝您有美好的一天!
    【解决方案2】:

    我认为从 MongoDB 版本 3.6 开始,您实际上可以使用 expr 运算符通过简单的过滤器来做到这一点。

    类似的东西:

    find({
      $expr: {
        $in: [
          "$amount",
          "$offers.amount"
        ]
      }
    })
    

    mongoplayground.net上查看实时示例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-09
      • 2023-03-31
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多