我目前的做法是:
var v = 'Value';
Collection.find({arrayToLookIn: v}).forEach(function(obj) {
if (obj.arrayToLookIn.indexOf(v) !== obj.arrayToLookIn.length - 1) {
// do stuff
}
}
我想知道是否有办法在find()
电话中指定这样的规则而不进行内部检查?
我查看了https://docs.mongodb.org/manual/tutorial/query-documents/#match-an-array-element,但没有发现我所寻求的内容。
第一个问题,请温柔:)
答案 0 :(得分:2)
您想要$where
,它可以使用JavaScript评估来匹配文档。所以在这里你要求评估代码测试每个数组元素,而不是最后一个:
Collection.find({
"arrayToLookIn": v,
"$where": function() {
var array = this.arrayToLookIn;
array.pop(); // remove last element
return array.some(function(el) { return el == 'Value' });
}
})
请注意,因为它是JavaScript发送到服务器的"值"需要在该代码中指定而不是使用变量。您可以选择将JavaScript代码构造为"字符串"将该变量作为文字加入并将其作为参数提交给$where
。
请注意,我离开了基本的平等匹配,因为$where
无法使用类似的索引匹配,因此它的工作就是过滤""过滤"输出匹配在最后一个元素上的结果,而不是测试每个文档以确定它是否在那里。
对于好奇的,就目前的MongoDB 3.0发布系列而言,使用聚合框架没有一种真正有效的方法,因此JavaScript评估是更好的选择。
你现在需要做一些愚蠢的事情,比如在$group
之后找到$unwind
中的最后一个元素,然后在另一个$match
之后$unwind
找出该值。如果值不止一次存在,它就没有效率且容易出错。
将来的版本将有一个$slice
运算符,可以像$redact
这样使用:
Collection.aggregate([
// Still wise to do this as mentioned earlier
{ "$match": { "arrayToLookIn": v } },
// Then only return if the match was not in the last element
{ "$redact": {
"$cond": {
"if": {
"$setIsSubset": [
[v],
{ "$slice": [
"$arrayToLookIn",
0,
{ "$subtract": [ { "$size": "$arrayToLookIn" }, 1 ] }
]}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
$setIsSubset
通过仅$slice
返回$size
的元素减去已通过0
删除了最后一个条目的数组的比较1
。
这应该比$where
更高效,因为当使用$slice
聚合的下一个版本可用时,它使用本机编码操作进行比较。
更不用说$unwind
也可以选择在将来的版本中包含索引位置。但即使添加了它,它仍然不是一个很好的选择。