Условие запроса MongoDb при сравнении двух полей

У меня есть коллекция T, с двумя полями: Grade1 и Grade2, и я хочу выбрать те, у которых условие Grade1 > Grade2, как я могу получить такой запрос, как в MySQL?

Select * from T Where Grade1 > Grade2

Ответ 1

Вы можете использовать $ где. Просто имейте в виду, что это будет довольно медленно (должен выполнять код 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 как описано в недавнем ответе

Ответ 2

Если ваш запрос состоит только из оператора $where, вы можете передать только выражение JavaScript:

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

Для большей производительности запустите агрегированную операцию с конвейером $redact для фильтрации документов, которые удовлетворяют данное условие.

Конвейер $redact включает в себя функциональные возможности $project и $match для реализации поля где он вернет все документы, соответствующие условию, используя $$KEEP и удалит из результатов конвейера те, которые не 't, используя переменную $$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 } }
])

Ответ 3

Вы можете использовать $ expr (оператор версии 3.6 mongo), чтобы использовать функции агрегирования в обычном запросе.

Сравнение query operators сравнения aggregation comparison operators.

Обычный запрос:

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

Запрос агрегации:

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

Ответ 4

Если производительность важнее, чем читаемость, и пока ваше условие состоит из простых арифметических операций, вы можете использовать конвейер агрегации. Сначала используйте $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 с за цикл

Ответ 5

{"_id": ObjectId ("5cb74e7d7c0b004588331dec"), "id": 10000505506.0, "shop_id": 1000113031, "__v": 0, "haraoes_extend_data": {"collection_id": []}, опубликовано ": false", is_deleted ": 0," body_html ":"

gggggggg

"," body_plain ": null," creation_at ": ISODate (" 2019-04-11T09: 30: 24.502Z ")," handle ":" imac "," images ": [{" src ":" https://product.hara.vn/1000113031/product/jessy-smith-534048-unsplash_af6078d228b2485098b519452e32f09f.jpg "," имя_файла ":" jessy-smith-534048-unsplash_af6078, 10000 ": 0505" 526505e050985e098 "create_at": ISODate ("2019-04-11T09: 30: 36.436Z"), "updated_at": ISODate ("2019-04-11T09: 30: 37.205Z"), "_id": ObjectId ("5cb83a293002553558094cbb"), "id": 10002753793.0, "attachment": null, "variable_ids": []}], "product_type": "imac", "publ_at": ISODate ("2019-04-11T09: 30: 24.445Z"), "ключ_области": "глобальный", "теги": "imac", "шаблон_суффикс": "продукт", "заголовок": "Imac", "updated_at": ISODate ("2019-04-12T10: 15: 41.312Z"), "варианты": [{"inventory_advance": {"qty_avaiable": 0, "qty_onhand": 0, "qty_commited": 0, "qty_incoming": 0}, "sync_ghn_wfs_status": "SYNCED", "sync_ghn_wfs_error": null, "штрих-код": "Я M00000001 "," inventory_management ":" haravan "," inventory_policy ":" deny "," sku ":" imac1 "," title ":" Заголовок по умолчанию "," option1 ":" Заголовок по умолчанию "," option2 ": null, "option3": null, "compare_at_price": 0, "грамм": 0, "inventory_quantity": 1, "old_inventory_quantity": 1, "inventory_quantity_adjustment": null, "position": 1, "price": 0, " product_id ": 10000505506.0," image_id ": null," require_shipping ": true," taxable ": true," creation_at ": ISODate (" 2019-04-11T09: 30: 24.502Z ")," updated_at ": ISODate (" 2019-04-12T10: 15: 41.312Z ")," _id ": ObjectId (" 5cb83a293002553558094cba ")," executement_service ": null," id ": 101559365," sync_ghn_wfs_id ": 43137," sync_ghn_wfs_at_ 201: ": -04-18T09: 17: 02.088Z ")}]," vendor ":" apple "," options ": [{" name ":" Title "," position ": 1," product_id ": 10000505506.0," _id ": ObjectId (" 5cb83a293002553558094cb9 ")," id ": 1003985654}]," only_hide_from_list ": false," not_allow_promotion ": false}

я должен найти документы имеют updated_at больше или равно sync_ghn_wfs_last_sync_at, но кажется, что они не работают

Ответ 6

но не работает между двумя десятичными полями. Как я могу сравнить 2 десятичных поля?