MongoDb比较两个字段的查询条件

我有一个集合T ,有两个字段: Grade1Grade2 ,我想select那些条件为Grade1 > Grade2 ,我怎样才能得到像在MySQL中的查询?

 Select * from T Where Grade1 > Grade2 

你可以使用$ where。 只要知道这将是相当缓慢(必须执行每个logging的Javascript代码),所以结合索引查询,如果可以的话。

 db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } ); 

或更紧凑:

 db.T.find( { $where : "this.Grade1 > this.Grade2" } ); 

如果您的查询只包含$where操作符,则只能传入JavaScriptexpression式:

 db.T.find("this.Grade1 > this.Grade2"); 

为了获得更好的性能,请运行具有$redactpipe道的集合操作来过滤满足给定条件的文档。

$redactpipe道集成了$project$match来实现字段级别的修订,在这里它将使用$$KEEP返回与条件匹配的所有文档,并从pipe道中删除那些与使用$$PRUNEvariables不匹配的结果。


运行以下集合操作,比使用$where对于大集合更有效地过滤文档$where因为这使用单个pipe道和本地MongoDB运算符,而不是使用$where JavaScript评估,这会降低查询速度:

 db.T.aggregate([ { "$redact": { "$cond": [ { "$gt": [ "$Grade1", "$Grade2" ] }, "$$KEEP", "$$PRUNE" ] } } ]) 

这是合并两个pipe道$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 } } ]) 

如果性能比可读性更重要,并且只要条件由简单的算术运算组成,则可以使用聚合pipe道。 首先,使用$ project来计算条件的左边(把所有的字段都放在左边)。 然后使用$ match来比较一个常量和filter。 这样你就避免了javascript的执行。 以下是我在python中的testing:

 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循环,最好是每循环4.54秒