MongoDB: структура агрегации: совпадение $ между полями

У меня есть тестовая коллекция с двумя документами:

> db.test.find().pretty()
{ "_id" : ObjectId("510114b46c1a3a0f6e5dd7aa"), "a" : 1, "b" : 2 }
{ "_id" : ObjectId("510114c86c1a3a0f6e5dd7ab"), "a" : 3, "b" : 1 }

С помощью фреймворка агрегации я хочу получать только те документы, в которых a больше b. $ gt получает только значения в аргументе, а не в полях ...

> db.test.aggregate([{"$match":{"$a":{"$gt":"$b"}}}])
{ "result" : [ ], "ok" : 1 } /* don't work*/

Есть предложения ?

заранее спасибо

С наилучшими пожеланиями


person hotips    schedule 24.01.2013    source источник
comment
Похоже, вы допустили ошибку в запросе агрегирования. Поле, которое вы хотите сопоставить, должно быть указано как a, а не $a, т.е. db.test.aggregate([{"$match":{"a":{"$gt":"$b"}}}])   -  person Quolonel Questions    schedule 10.02.2016
comment
@QuolonelQuestions, который по-прежнему не будет работать, MongoDB не будет использовать значение поля b, он будет использовать $b как правую часть сравнения. Это можно проверить, выполнив db.test.aggregate([{"$match":{"a":{"$eq":"$a"}}}]). Нулевые результаты будут возвращены.   -  person Paul    schedule 07.02.2017
comment
Вы можете использовать выражение агрегирования в регулярном запросе версии 3.6. Что-то вроде db.test.find( {"$expr": {"$gt": ["$a", "$b"]}}) и в совокупности через db.test.aggregate( {"$match":{"$expr": {"$gt": ["$a", "$b"]}}})   -  person s7vr    schedule 14.12.2017


Ответы (2)


Хм, без особого тестирования с моей стороны, я скажу, что вы можете использовать $cmp для этого:

http://docs.mongodb.org/manual/reference/aggregation/cmp/#_S_cmp

db.test.aggregate([
    {$project: {
        // All your other fields here
        cmp_value: {$cmp: ['$a', '$b']}
    }},
    {$match: {cmp_value: {$gt: 0}}} 
])

Возможно, есть лучший способ, но у меня нет установки MongoDB для тестирования.

person Sammaye    schedule 24.01.2013
comment
Могу ли я узнать, как использовать вышеуказанный запрос mongdb с языком php. Я использовал вышеуказанный метод, не работает. Пожалуйста, помогите с этим. - person sankar muniyappa; 06.04.2016
comment
@shankarmsr С новым драйвером: (new \MongoDB\Client())->db->collection->aggregate([['$project' => ['cmp_value' => ['$cmp' => ['$a', '$b']]]], ['$match' => ['cmp_value' => ['$gt' => 0]]]]) или что-то в этом роде - person Sammaye; 06.04.2016
comment
Позвольте мне проверить ваш ответ. Надеюсь, он будет работать нормально - person sankar muniyappa; 27.04.2016

Используйте оператор $expr.

В версии 3.6 $expr можно создавать выражения запросов, которые сравнивают поля из одного и того же документа.

Сравните два поля из одного документа (пример взят непосредственно из Документы MongoDB):

Рассмотрим ежемесячный сборник бюджета со следующими документами:

{ "_id" : 1, "category" : "food", "budget": 400, "spent": 450 }
{ "_id" : 2, "category" : "drinks", "budget": 100, "spent": 150 }
{ "_id" : 3, "category" : "clothes", "budget": 100, "spent": 50 }
{ "_id" : 4, "category" : "misc", "budget": 500, "spent": 300 }
{ "_id" : 5, "category" : "travel", "budget": 200, "spent": 650 }

Следующая операция использует $expr для поиска документов, в которых потраченная сумма превышает бюджет:

db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )

Операция возвращает следующие результаты:

{ "_id" : 1, "category" : "food", "budget" : 400, "spent" : 450 }
{ "_id" : 2, "category" : "drinks", "budget" : 100, "spent" : 150 }
{ "_id" : 5, "category" : "travel", "budget" : 200, "spent" : 650 }
person Govind Rai    schedule 22.06.2019