コレクションT
に2つのフィールドGrade1
およびGrade2
があり、条件Grade1 > Grade2
を持つコレクションを選択したいのですが、MySQLのようなクエリを取得するにはどうすればよいですか?
Select * from T Where Grade1 > Grade2
$ whereを使用できます。かなり遅い(すべてのレコードでJavaScriptコードを実行する必要がある)ので、可能であればインデックス付きクエリと組み合わせてください。
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );
以上のコンパクト:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );
最近の回答 で説明されているように$expr
を使用できます
クエリが $where
演算子のみで構成されている場合、JavaScript式のみを渡すことができます。
db.T.find("this.Grade1 > this.Grade2");
パフォーマンスを向上させるには、$redact
パイプラインを持つ集約操作を実行して、指定された条件を満たすドキュメントをフィルタリングします。
$redact
パイプラインには$project
の機能が組み込まれていますおよび$match
は、 を使用して条件に一致するすべてのドキュメントを返すフィールドレベルの墨消しを実装します$$KEEP
およびパイプラインの結果から、$$Prune
変数を使用して一致しない結果を削除します。
次の集約操作を実行すると、 $where
を使用するよりも効率的にドキュメントをフィルタリングします。これは、単一のパイプラインとネイティブMongoDB演算子を使用するため、 $where
を使用したJavaScript評価。クエリが遅くなる可能性があります。
db.T.aggregate([
{
"$redact": {
"$cond": [
{ "$gt": [ "$Grade1", "$Grade2" ] },
"$$KEEP",
"$$Prune"
]
}
}
])
これは、2つのパイプライン$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 version operator)を使用して、通常のクエリで集計関数を使用できます。
比較 query operators
vs aggregation 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秒