Answers:
您可以使用$ where。请注意,这会相当慢(必须在每条记录上执行Javascript代码),因此请与索引查询结合使用。
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );
或更紧凑:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );
您可以$expr
按照最近的答案中的描述使用
$where: function() { return this.Grade1 - this.Grade2 > variable }
?
db.T.find({$where: function() {return this.startDate == ISODate("2017-01-20T10:55:08.000Z");}});
它什么也不会返回,即使集合中的文档之一也是如此ISODate("2017-01-20T10:55:08.000Z")
。但是<=
,>=
似乎工作。任何想法?
this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
您可以使用$ expr(3.6 mongo版本运算符)在常规查询中使用聚合函数。
比较query operators
与aggregation comparison operators
。
常规查询:
db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})
汇总查询:
db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})
如果您的查询仅包含$where
运算符,则可以仅传递JavaScript表达式:
db.T.find("this.Grade1 > this.Grade2");
为了获得更高的性能,请运行一个聚合操作,该操作具有一个$redact
管道来过滤满足给定条件的文档。
该$redact
管道包含的功能$project
,并$match
实现现场级新版本,其中将返回使用符合条件的所有文件$$KEEP
,并从管道结果那些不使用匹配$$PRUNE
变量。
与使用$where
大型集合相比,运行以下聚合操作比使用大型集合更有效地过滤文档,因为这使用单个管道和本机MongoDB运算符,而不是使用进行JavaScript评估$where
会降低查询速度:
db.T.aggregate([
{
"$redact": {
"$cond": [
{ "$gt": [ "$Grade1", "$Grade2" ] },
"$$KEEP",
"$$PRUNE"
]
}
}
])
这是结合了两个管道$project
和$match
以下内容的简化版本:
db.T.aggregate([
{
"$project": {
"isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] },
"Grade1": 1,
"Grade2": 1,
"OtherFields": 1,
...
}
},
{ "$match": { "isGrade1Greater": 1 } }
])
使用MongoDB 3.4及更高版本:
db.T.aggregate([
{
"$addFields": {
"isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] }
}
},
{ "$match": { "isGrade1Greater": 1 } }
])
如果性能比可读性更重要,并且只要条件由简单的算术运算组成,则可以使用聚合管道。首先,使用$ project计算条件的左侧(将所有字段移到左侧)。然后使用$ match与常量和过滤器进行比较。这样您可以避免执行JavaScript。以下是我在python中的测试:
import pymongo
from random import randrange
docs = [{'Grade1': randrange(10), 'Grade2': randrange(10)} for __ in range(100000)]
coll = pymongo.MongoClient().test_db.grades
coll.insert_many(docs)
使用聚合:
%timeit -n1 -r1 list(coll.aggregate([
{
'$project': {
'diff': {'$subtract': ['$Grade1', '$Grade2']},
'Grade1': 1,
'Grade2': 1
}
},
{
'$match': {'diff': {'$gt': 0}}
}
]))
1个循环,每个循环最好1:192 ms
使用find和$ where:
%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))
1个循环,每个循环的最佳时间为1:4.54 s