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

比较两个字段时的MongoDb查询条件,mongodb,compare,Mongodb,Compare,我有一个集合T,有两个字段:Grade1和Grade2,我想选择那些条件为Grade1>Grade2的,我怎样才能得到类似MySQL的查询 Select * from T Where Grade1 > Grade2 你可以在哪里使用$where。请注意,它将相当慢(必须在每个记录上执行Javascript代码),因此如果可以,请与索引查询结合使用 db.T.find( { $where: function() { return this.Grade1 > this.Grade2 }

我有一个集合
T
,有两个字段:
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" } );
mongodb版本3.6的UPD+
您可以使用

中所述的
$expr
,如果您的查询只包含运算符,您可以只传入JavaScript表达式:

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

为了获得更好的性能,请运行具有管道的聚合操作,以筛选满足给定条件的文档

管道包含了的功能,以实现字段级的编校,其中它将使用变量返回与条件匹配的所有文档,并从管道结果中删除不匹配的文档


运行以下聚合操作比使用大型集合更有效地过滤文档,因为这使用单个管道和本机MongoDB运算符,而不是使用JavaScript求值,这会降低查询速度:

db.T.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$gt": [ "$Grade1", "$Grade2" ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])
这是合并两条管道的更简化版本

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秒

您可以使用(3.6 mongo版本运算符)在常规查询中使用聚合函数

比较

常规查询:

db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})
聚合查询:

db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})

哦,我明白了,只要联合使用javascript或其他shell脚本,谢谢你们两个!您也可以做得更紧凑一些…>db.T.find({$where:“this.Grade1>this.Grade2”});当我尝试
db.T.find({$where:function(){return this.Grade1-this.Grade2>variable}时,{$where:function(){return this.startDate==ISODate(“2017-01-20T10:55:08.000Z”);}),我怎么能
$where:function(){
它不返回任何内容,即使集合中的一个文档是
ISODate(“2017-01-20T10:55:08.000Z”)
。但是
=
似乎很有效。有什么想法吗?@Catyes可能有点晚了。。。但是在两个日期之间进行==比较时,纯javascript总是返回false。然而,Mongo允许您在查询中搜索日期之间的精确匹配。一种解决方法是使用.getTime()转换为毫秒或其他形式:
this.startDate.getTime()==ISODate(“2017-01-20T10:55:08.000Z”).getTime()
最后一种方法似乎对我不起作用。isGrade1Greater字段已正确添加和计算,但由于某种原因,无论isGrade1Greater的值是多少,查询都会匹配所有行。这种行为的原因可能是什么?编辑:没关系,我并没有将数组传递给aggregate(),而是将每个聚合本身作为一个参数传递,但没有传递。