Состояние в MongoDB запрос на сравнение 2 поля
у меня есть коллекция T С 2 полями: Grade1 и Grade2 и я хочу, чтобы выбрать те, с условием Grade1 > Grade2, как я могу получить запрос, как в MySQL?
Select * from T Where Grade1 > Grade2
4 ответа:
вы можете использовать $where. Просто имейте в виду, что это будет довольно медленно (должен выполнять код Javascript на каждой записи), поэтому объедините с индексированными запросами, если сможете.
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );или более компактно:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );UPD для mongodb V. 3. 6+
можно использовать
$exprкак описано в недавний ответ
если ваш запрос состоит только из
$whereоператор, вы можете передать только выражение JavaScript:db.T.find("this.Grade1 > this.Grade2");
для повышения производительности запустите агрегатную операцию, которая имеет
$redactконвейер для фильтрации документов, удовлетворяющих данному условию.The
$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 } } ])
можно использовать $expr (оператор версии 3.6 mongo) для использования функций агрегации в регулярном запросе.
сравнить
query operatorsvsaggregation comparison operators.Регулярный Запрос:
db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})Запрос Агрегации:
db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})
в случае, если производительность важнее, чем читаемость, и пока ваше условие состоит из простых арифметических операций, вы можете использовать конвейер агрегации. Во-первых, используйте $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 s за цикл