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


108

我有一个T具有2个字段的集合:Grade1Grade2,我想选择带条件的那些Grade1 > Grade2,如何获得像MySQL一样的查询?

Select * from T Where Grade1 > Grade2

Answers:


120

您可以使用$ where。请注意,这会相当慢(必须在每条记录上执行Javascript代码),因此请与索引查询结合使用。

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

或更紧凑:

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

适用于mongodb的UPD v.3.6 +

您可以$expr按照最近的答案中的描述使用


糟糕,我明白了,只是联合使用javascript或其他shell脚本,谢谢你们!
Diego Cheng 2010年

16
您也可以使它更加紧凑...> db.T.find({$ where:“ this.Grade1> this.Grade2”});
贾斯汀·詹金斯

我怎么能 $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")。但是<=>=似乎工作。任何想法?
cateyes

@cateyes也许有点晚...但是纯JavaScript总是在两个日期之间进行==比较时返回false。但是,Mongo可让您搜索查询中日期之间的精确匹配。一种解决方法是使用.getTime()转换为毫秒或其他方式:this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
leinaD_natipaC


39

如果您的查询仅包含$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 } }
])

最后一个似乎不与我合作。正确添加并评估了isGrade1Greater字段,但是由于某种原因,无论isGrade1Greater的值如何,查询都匹配所有行。这种行为的原因可能是什么?编辑:没关系,我没有将数组传递给aggregate(),而是将每个聚合作为参数本身错过了。
ThatBrianDude

13

如果性能比可读性更重要,并且只要条件由简单的算术运算组成,则可以使用聚合管道。首先,使用$ 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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.