【发布时间】:2010-12-14 18:00:37
【问题描述】:
我有一个集合 T,有 2 个字段:Grade1 和 Grade2,我想选择条件为 Grade1 > Grade2 的那些,我怎样才能获得类似 MySQL 中的查询?
Select * from T Where Grade1 > Grade2
【问题讨论】:
我有一个集合 T,有 2 个字段:Grade1 和 Grade2,我想选择条件为 Grade1 > Grade2 的那些,我怎样才能获得类似 MySQL 中的查询?
Select * from T Where Grade1 > Grade2
【问题讨论】:
您可以使用 $where。请注意,它会相当慢(必须在每条记录上执行 Javascript 代码),所以如果可以的话,请结合索引查询。
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );
或更紧凑:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );
您可以按照recent answer 中的说明使用$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 运算符,而不是使用 $where 进行 JavaScript 评估,这会减慢查询速度:
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 毫秒
使用 find 和 $where:
%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))
1 个循环,最好的 1:每个循环 4.54 秒
【讨论】: