我有这样的文件:
{
name: 'john',
array: [{foo: 3, bar: 1},{foo:1, bar: 0},...]
}
我想找到foo和bar之间差异小于数组中某个条目中某个值的所有文档。我目前正在尝试使用$ where查询。我找回一个空列表。我的问题是我使用承诺的方式还是我使用$ where的方式?
代码:
MongoClient.connect(config.database)
.then(function(db) {
return db.collection('MyCollection')
})
.then(function (collection) {
return collection.find(
{ $where:
function() {
for(var i = 0; i < this.array.length; i++) {
if((this.array[i].foo - this.array[i].bar) < 2) {
return true;
}
}
return false;
}
}
)
})
.then(function(cursor) {
return cursor.toArray()
})
.then(function(arr) {
console.log(arr)
})
.catch(function(err) {
throw err;
});
答案 0 :(得分:0)
使用聚合框架和 $redact
管道运算符,您可以使用 $cond
运算符处理逻辑条件并使用特殊操作 $$KEEP
至&#34;保持&#34;逻辑条件为真的文档或 $$PRUNE
到&#34;删除&#34;条件错误的文件。
此操作类似于具有 $project
管道,该管道选择集合中的字段并创建一个新字段,其中包含逻辑条件查询的结果,然后是后续的 $match
,但 $redact
使用效率更高的单个管道阶段。
考虑以下展示上述概念的示例:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$anyElementTrue": {
"$map": {
"input": "$array",
"as": "el",
"in": {
"$lt": [
{ "$subtract": ["$$el.foo", "$$el.bar"] },
2
]
}
}
}
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
在上面的示例中, $anyElementTrue
和 $map
组合的工作原理是,如果数组中的任何元素实际存在它的foo和bar值之间的差异小于2,那么这是一个真正的匹配,文档是&#34;保持&#34;。否则它将被修剪&#34;并丢弃。
因此,您重构的代码应该看起来像
MongoClient.connect(config.database)
.then(function(db) {
return db.collection('MyCollection')
})
.then(function (collection) {
return collection.aggregate([
{
"$redact": {
"$cond": [
{
"$anyElementTrue": {
"$map": {
"input": "$array",
"as": "el",
"in": {
"$lt": [
{ "$subtract": ["$$el.foo", "$$el.bar"] },
2
]
}
}
}
},
"$$KEEP",
"$$PRUNE"
]
}
}
]);
})
.then(function(cursor) {
return cursor.toArray()
})
.then(function(arr) {
console.log(arr)
})
.catch(function(err) {
throw err;
});
这会显着改善性能,因为 $redact
运算符使用MongoDB的本机运算符,而查询操作使用 $where
运算符调用JavaScript引擎来评估每个文档的Javascript代码,并检查每个文档的条件。
由于MongoDB在 $where
表达式和非 {{3}之前评估非 $where
查询操作,因此速度非常慢查询语句可以使用索引。
建议您与索引查询结合使用,以便查询可能更快。但是,建议您使用JavaScript表达式和 $where
运算符作为最后的手段,当您无法以任何其他方式构建数据时,或者当您处理一小部分数据。