将嵌套文档与MongoDB中的父字段进行比较

5
考虑以下集合,其中父文档具有值为 100000amount 字段,并且嵌入的文档数组具有相同的 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来实现这个功能,避免使用聚合查询,但也许这是不可能的。

2个回答

4

标准查询无法“比较”文档中的值。这实际上是使用.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" ] }
      }
    }
  }}
])

但主要原则当然是“减少”返回文档的数量,仅将实际匹配条件作为“第一”优先级。否则,您只会进行不必要的计算和工作,这需要花费时间和资源,并得到您随后会丢弃的结果。

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


非常感谢,如果报价文档有自己的集合并引用其他文档,会更容易吗?这种汇总似乎需要很多工作,我是说从性能方面考虑,将报价文档放在自己的集合中并引用其他文档的ID是否更好? - Stefan Konno
@StefanKonno 从性能角度来看,将事物放入另一个集合中是更糟糕的。连接成本高昂。这就是为什么你应该首先使用MongoDB的原因。没有“简单”的方法来比较一个字段和另一个字段。任何方法都有成本,关系型数据库也是如此。 - Neil Lunn
再次感谢,我会试一试的。非常感谢您的努力,祝您愉快! - Stefan Konno

1

我认为自MongoDB 3.6版本以来,您可以使用expr运算符的简单过滤器实现此操作。

大概是这样的:

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

mongoplayground.net上查看实时示例。


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