Pertanyaan Kondisi permintaan MongoDb pada perbandingan 2 bidang


Saya memiliki koleksi T, dengan 2 bidang: Grade1 dan Grade2, dan saya ingin memilih mereka dengan kondisi Grade1 > Grade2, bagaimana saya bisa mendapatkan pertanyaan seperti di MySQL?

Select * from T Where Grade1 > Grade2

75
2017-12-14 18:00


asal


Jawaban:


Anda dapat menggunakan $ di mana. Sadarilah itu akan cukup lambat (harus mengeksekusi kode Javascript pada setiap catatan), jadi gabungkan dengan kueri terindeks jika Anda bisa.

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

atau lebih ringkas:

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

UPD untuk mongodb v.3.6 +

Kamu dapat memakai $expr seperti yang dijelaskan dalam jawaban terbaru


98
2017-12-14 19:43



Jika permintaan Anda hanya terdiri dari $where operator, Anda dapat mengirimkan hanya ekspresi JavaScript:

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

Untuk kinerja yang lebih baik, jalankan operasi gabungan yang memiliki $redact pipa untuk menyaring dokumen yang memenuhi ketentuan yang diberikan.

Itu $redact pipa menggabungkan fungsionalitas $project dan $match untuk menerapkan redaksi tingkat lapangan di mana ia akan mengembalikan semua dokumen yang cocok dengan kondisi yang digunakan $$KEEP dan menghapus dari hasil pipeline mereka yang tidak cocok menggunakan $$PRUNE variabel.


Menjalankan operasi gabungan berikut menyaring dokumen lebih efisien daripada menggunakan $where untuk koleksi besar karena ini menggunakan jaringan pipa tunggal dan operator MongoDB asli, daripada evaluasi JavaScript dengan $where, yang dapat memperlambat kueri:

db.T.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$gt": [ "$Grade1", "$Grade2" ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

yang merupakan versi yang lebih sederhana dari menggabungkan dua jalur pipa $project dan $match:

db.T.aggregate([
    {
        "$project": {
            "isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] },
            "Grade1": 1,
            "Grade2": 1,
            "OtherFields": 1,
            ...
        }
    },
    { "$match": { "isGrade1Greater": 1 } }
])

Dengan MongoDB 3.4 dan yang lebih baru:

db.T.aggregate([
    {
        "$addFields": {
            "isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] }
        }
    },
    { "$match": { "isGrade1Greater": 1 } }
])

31
2018-03-26 14:43



Dalam hal kinerja lebih penting daripada keterbacaan dan selama kondisi Anda terdiri dari operasi aritmatika sederhana, Anda dapat menggunakan pipa agregasi. Pertama, gunakan $ project untuk menghitung sisi kiri kondisi (ambil semua field ke sisi kiri). Kemudian gunakan $ match untuk membandingkan dengan konstanta dan filter. Dengan cara ini Anda menghindari eksekusi javascript. Di bawah ini adalah tes saya di 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)

Menggunakan agregat:

%timeit -n1 -r1 list(coll.aggregate([
    {
        '$project': {
            'diff': {'$subtract': ['$Grade1', '$Grade2']},
            'Grade1': 1,
            'Grade2': 1
        }
    },
    {
        '$match': {'diff': {'$gt': 0}}
    }
]))

1 loop, terbaik 1: 192 md per loop

Menggunakan find dan $ di mana:

%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))

1 loop, terbaik 1: 4,54 s per loop


11
2018-06-23 21:08



Kamu dapat memakai $ expr (Operator versi 3,6 mongo) untuk menggunakan fungsi agregasi dalam permintaan biasa.

Membandingkan query operators vs aggregation comparison operators.

Pertanyaan Reguler:

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

Kueri Agregasi:

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

10
2018-01-23 21:14