我想在数组中搜索一个字段,并想知道数组中该字段的索引是否可以找到它? 例如:
doc1: {id:123, hobby:['chess','cards','dance']}
doc2: {id:123, hobby:['cards','dance','chess']}
我想只搜索有的文件
chess
和cards
,但只有chess
之前card
的{{1}}。所以在doc1
。
答案 0 :(得分:3)
您可以使用$where
运算符执行此操作,将其与$all
运算符耦合以保持合理的性能:
db.test.find({
// Find all the docs where hobby contains both 'cards' and 'chess'
hobby: {$all: ['cards', 'chess']},
// Of those, run this $where query that evaluates the indexes of the matched elements
$where: "this.hobby.indexOf('cards') > this.hobby.indexOf('chess')"
})
在hobby
上添加索引以获得最佳效果。
答案 1 :(得分:0)
为了获得最佳性能,您实际上将.aggregate()
与$match
阶段一起用于“查询”,以缩小与包含$all
数组中元素的文档的可能匹配,以及$redact
从剩余结果中过滤:
db.test.aggregate([
{ "$match": { "hobby": { "$all": [ "chess", "cards" ] } } },
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$filter": {
"input": "$hobby",
"as": "hobby",
"cond": {
"$or": [
{ "$eq": [ "$$hobby", "chess" ] },
{ "$eq": [ "$$hobby", "cards" ] }
]
}
}},
["chess","cards"]
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
有效的原因是因为$filter
只能返回与此处给出的条件匹配的元素,并将它们以相同的顺序返回“,其中它们存储在原始文件中文献。
一旦“过滤”下来,如果原始数组中的元素确实按此顺序排列,那么数组应该是内容["chess","cards"]
的完全匹配。
请注意,尽管它“看起来”更简单,但您无法使用"set operators"来测试它,因为“sets”实际上并不被认为是有序的。
所以你需要维护顺序的东西,而$filter
实际上是唯一能够以有效的方式对数组内容做到这一点的事情。因此,解决方案确实仅限于需要MongoDB 3.2或更高版本才能实际运行。
对于旧版本,请参阅answer from JohnnyHK使用$where
对数组元素应用.indexOf()
测试作为使用$all
的附加过滤器。
但是如果你有MongoDB 3.2和可用的运算符,那么聚合框架可用的本机编码操作比$where
的JavaScript评估运行得快得多,应该优先使用。