Saya memiliki koleksi T
, dengan 2 bidang: Grade1
dan Grade2
, dan saya ingin memilih yang kondisinya Grade1 > Grade2
, bagaimana saya bisa mendapatkan kueri seperti di MySQL?
Select * from T Where Grade1 > Grade2
Saya memiliki koleksi T
, dengan 2 bidang: Grade1
dan Grade2
, dan saya ingin memilih yang kondisinya Grade1 > Grade2
, bagaimana saya bisa mendapatkan kueri seperti di MySQL?
Select * from T Where Grade1 > Grade2
Jawaban:
Anda bisa menggunakan $ where. Perlu diketahui bahwa ini akan cukup lambat (harus mengeksekusi kode Javascript pada setiap record) jadi gabungkan dengan query yang diindeks jika Anda bisa.
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );
atau lebih kompak:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );
Anda dapat menggunakan $expr
seperti yang dijelaskan dalam jawaban terbaru
$where: function() { return this.Grade1 - this.Grade2 > variable }
?
db.T.find({$where: function() {return this.startDate == ISODate("2017-01-20T10:55:08.000Z");}});
tidak mengembalikan apa-apa, bahkan salah satu dokumen dalam koleksi tersebut ISODate("2017-01-20T10:55:08.000Z")
. Tapi <=
dan >=
sepertinya berhasil. ada ide?
this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
Anda dapat menggunakan $ expr (operator versi 3.6 mongo) untuk menggunakan fungsi agregasi dalam kueri reguler.
Bandingkan 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"]}}})
Jika kueri Anda hanya terdiri dari $where
operator, Anda dapat meneruskan hanya ekspresi JavaScript:
db.T.find("this.Grade1 > this.Grade2");
Untuk performa yang lebih baik, jalankan operasi agregat yang memiliki $redact
pipeline untuk memfilter dokumen yang memenuhi kondisi yang diberikan.
The $redact
pipa menggabungkan fungsi $project
dan $match
untuk menerapkan tingkat redaksi bidang di mana ia akan mengembalikan semua dokumen yang cocok kondisi menggunakan $$KEEP
dan menghapus dari hasil pipa mereka yang tidak cocok menggunakan $$PRUNE
variabel.
Menjalankan operasi agregat berikut memfilter dokumen secara lebih efisien daripada menggunakan $where
untuk koleksi besar karena ini menggunakan pipeline tunggal dan operator MongoDB asli, bukan dengan evaluasi JavaScript $where
, yang dapat memperlambat kueri:
db.T.aggregate([
{
"$redact": {
"$cond": [
{ "$gt": [ "$Grade1", "$Grade2" ] },
"$$KEEP",
"$$PRUNE"
]
}
}
])
yang merupakan versi yang lebih sederhana dari menggabungkan dua pipeline $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 } }
])
Jika performa lebih penting daripada keterbacaan dan selama kondisi Anda terdiri dari operasi aritmatika sederhana, Anda dapat menggunakan pipeline agregasi. Pertama, gunakan $ project untuk menghitung sisi kiri kondisi (ambil semua bidang ke sisi kiri). Kemudian gunakan $ match untuk membandingkan dengan konstanta dan filter. Dengan cara ini Anda menghindari eksekusi javascript. Di bawah ini adalah pengujian saya dengan 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 ms per loop
Menggunakan find dan $ where:
%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))
1 loop, terbaik 1: 4,54 d per loop