[英]Find a document that contains a specific value in an array but not if it's the last element
我目前的做法是:
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但没有发现我在寻找什么。
第一个问题,请温柔:)
您需要$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 评估是更好的选择。
您目前需要做一些愚蠢的事情,例如在$unwind
之后找到$group
的最后一个元素,然后在另一个$unwind
之后$match
出该值。 如果值存在多次,则效率不高且容易出错。
未来版本将有一个$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
通过只返回从0
到$size
减1
元素来比较通过$slice
删除它的最后一个条目的数组。
这应该比$where
更有效$where
因为它使用本机编码操作进行比较,当具有该$slice
用于聚合的下一个版本可用时。
更不用说$unwind
还可以选择在未来版本中包含索引位置。 但即使添加了它,它仍然不是一个很好的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.