使用 mongoDB 将嵌入文档与父字段进行比较

Ste*_*nno 5 mongodb mongodb-query aggregation-framework

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

{
"_id" : ObjectId("5975ce5f05563b6303924914"),
"amount" : 100000,
"offers" : [ 
    {
        "amount": 100000
    }
]
Run Code Online (Sandbox Code Playgroud)

}

有什么方法可以匹配至少一个嵌入文档offer与父文档数量相同的所有对象?

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

find({ offers: { $elemMatch: { loan_amount: 100000 } } })
Run Code Online (Sandbox Code Playgroud)

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

find({ offers: { $elemMatch: { loan_amount: "parent.loan_amount" } } })
Run Code Online (Sandbox Code Playgroud)

感谢您的任何建议。我希望用$eqor做到这一点$elemMatch,并避免聚合,但也许这是不可能的。

谢谢!

Nei*_*unn 4

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

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

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

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

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

如果您实际上只想要“匹配的数组元素”,那么您将添加一个$filterin 投影:

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" ] }
      }
    }
  }}
])
Run Code Online (Sandbox Code Playgroud)

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

因此,优先考虑的是首先“过滤”,然后“重塑”。