如何比较同一文档中数组中的元素?

时间:2017-11-13 03:21:39

标签: javascript mongodb performance

我找到了比较同一MongoDB集合中的差异文档中数组之间的值的方法,但是如何在一个文档中按照索引比较同一数组中的元素?这是有问题的条目:

{ "_id" : ObjectId("1"), "arr" : [ { "int" : 100 }, { "int" : 10 } ] }

我有一个包含大量这些条目的集合(当然在这里简化),我想查询集合,检查每个条目,以及arr[0].int > arr[1].int是否返回这些文档。更好的是具有用于确定index 1处的元素与index 0处的元素的差异的逻辑。所以在这种情况下,例如,index 1 is 10 times less than index 0

以下工作用于查询mongoDoc中的元素是否大于给定值:

db.collection.find( { "arr.0.int" : { $gt: 10 }})

我玩过这个 - 但事实证明没有任何用处。 由于数据集很大 - 性能考虑因素很棒!

谢谢!

1 个答案:

答案 0 :(得分:2)

这里的基本情况是简单地应用$redact$arrayElemAt的条件来检查每个索引:

db.collection.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$gt": [
          { "$arrayElemAt": ["$arr.int", 0] },
          { "$arrayElemAt": ["$arr.int", 1] }
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

这是一个特殊的管道阶段,以满足"if"条件"then"的方式"$$KEEP"使用"else"我们"$$PRUNE"结果中的文档,否则{{1}我们db.collection.aggregate([ { "$match": { "$expr": { "$gt": [ { "$arrayElemAt": ["$arr.int", 0] }, { "$arrayElemAt": ["$arr.int", 1] } ] } }} ]) 来自结果。

这使用本机运算符,并且作为“高性能”,因为依赖于计算的查询将会得到。

MongoDB 3.6使用$cond

允许更短的语法
.find()

甚至可以在db.collection.find({ "$expr": { "$gt": [ { "$arrayElemAt": ["$arr.int", 0] }, { "$arrayElemAt": ["$arr.int", 1] } ] } })

中实际使用
db.collection.find({
  "$where": "return this.arr[0].int > this.arr[1].int"
})

自发布以来的所有版本都通过$expr支持JavaScript评估:

.find()

但是,由于这需要为每个文档评估JavaScript表达式,因此它不像使用本机运算符那样高效。

另外,获得“比率”响应的唯一方法是使用聚合管道,该管道实际上可以“更改”返回的结果,而db.collection.aggregate([ { "$redact": { "$cond": { "if": { "$gt": [ { "$arrayElemAt": ["$arr.int", 0] }, { "$arrayElemAt": ["$arr.int", 1] } ] }, "then": "$$KEEP", "else": "$$PRUNE" } }}, { "$addFields": { "ratio": { "$divide": [ { "$arrayElemAt": ["$arr.int", 1] }, { "$arrayElemAt": ["$arr.int", 0] } ] } }} ]) 查询无法做到:

{ "arr": [{ "int": 100 },{ "int": 10 }], "firstIsGreater": true }

无论如何,“计算作为条件”没有什么好处,因为除了遍历集合中的每个文档并查看它是否符合条件之外,没有其他选择。

因此,如果这是“通用逻辑”,那么您最好将其存储在文档中。即:

   class UserRegistrationForm(forms.Form):
        username = forms.CharField(
            required = True,
            label = 'Username',
            max_length = 32
        )
        password = forms.CharField(
            required = True,
            label = 'Password',
            max_length = 32,
            widget = forms.PasswordInput()
        )

然后你实际上“可以”以有效的方式使用索引进行选择。因此,当您更改文档中的内容时,应由您的应用程序逻辑来编写此条件,从而使您不需要进行此类计算。

如果您无法以这种方式进行建模和存储,那么您可以使用任何一种形式进行计算。因此,通常最好先考虑一下为什么你认为首先需要这样一个计算条件。