如何比较同一文档中数组中的元素?
我找到了比较同一 MongoDB 集合中不同文档中数组值的方法,但是 如何按索引比较同一文档中同一数组中的元素? 以下是相关条目:
{ "_id" : ObjectId("1"), "arr" : [ { "int" : 100 }, { "int" : 10 } ] }
我有一个包含大量此类条目的集合(当然这里进行了简化),我想查询该集合,检查每个条目,如果
arr[0].int > arr[1].int
则返回这些文档。更好的方法是使用逻辑来确定
索引 1
处的元素与
索引 0
处的元素的百分比差异。因此,在此示例中,例如,
索引 1 比索引 0 小 10 倍
以下方法可用于查询 mongoDoc 中的元素是否大于给定值:
db.collection.find( { "arr.0.int" : { $gt: 10 }})
我试过这个 - 但没有什么用。 由于数据集很大 - 性能考虑会很棒!
谢谢!
这里的基本情况是简单地应用
$redact
和
$arrayElemAt
的条件,以便检查每个索引:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$gt": [
{ "$arrayElemAt": ["$arr.int", 0] },
{ "$arrayElemAt": ["$arr.int", 1] }
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
这是一个特殊的管道阶段,它使用
$cond
以满足
“if”
条件
“then”
我们
“$$KEEP”
结果中的文档,否则
“else”
我们
“$$PRUNE”
结果中的文档。
这使用本机运算符,并且与依赖于计算的查询一样“高效”。
MongoDB 3.6 允许使用
$expr
对此使用更简短的语法:
db.collection.aggregate([
{ "$match": {
"$expr": {
"$gt": [
{ "$arrayElemAt": ["$arr.int", 0] },
{ "$arrayElemAt": ["$arr.int", 1] }
]
}
}}
])
甚至可以在
.find()
中使用:
db.collection.find({
"$expr": {
"$gt": [
{ "$arrayElemAt": ["$arr.int", 0] },
{ "$arrayElemAt": ["$arr.int", 1] }
]
}
})
并且自发布以来的所有版本都支持通过
$where
:
db.collection.find({
"$where": "return this.arr[0].int > this.arr[1].int"
})
但是,由于这需要对每个文档的 JavaScript 表达式进行评估,因此它的性能不如使用本机运算符。
此外,获取“比率”响应的唯一方法是使用聚合管道,该管道实际上可以“改变”返回的结果,而
.find()
查询无法做到这一点:
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 }
然后您实际上 “可以” 以有效的方式使用索引进行选择。因此,当您更改文档中的内容时,编写此条件将取决于您的应用程序逻辑,从而让您不需要这样的计算。
如果您不能以这种方式建模和存储,那么任何一种形式的计算都是您所拥有的。所以通常最好先考虑一下为什么您认为您需要这样一个计算条件。