学習MongoDB--(4-1):MongoDBクエリー(基本クエリー条件オペレータ紹介)


前述の学習から,モンゴDBではfind関数を用いてクエリを行うことが分かった.クエリは、最終的に、このセット内のすべてのドキュメントに0個のドキュメントを含むセット内のドキュメントのサブセットを返します.
【最初のクエリパラメータ】
find関数の最初のパラメータは、セット内のどのようなドキュメントをクエリーするかを示すドキュメントです.すべてのドキュメントをクエリーする場合は、find関数を呼び出すパラメータを持たないか、空のドキュメント{}の最初のパラメータを次の例に示します.
> db.people.find();
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
> db.people.find({});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
>

クエリー・パラメータを表す最初のドキュメントについて、どのように理解すればいいですか?例えばdbを実行しますpeople.find(「age」:18})は、この関数が実際にキー「age」の値が18のドキュメントをクエリーすることを示し、キー「age」の値が18に等しくない、またはこのキーが存在しないドキュメントはクエリーされません.例えばdb.people.find(「name」:「jimmy」,「age」:18})は、実際にはクエリーキー「name」の値が「jimmy」であり、キー「age」の値が18のドキュメント、すなわちクエリードキュメントの各条件がANDの関係であることを示す!
最初のパラメータを使用する場合は、クエリードキュメントのキー値ペアの値が定数である必要があります.
【2番目のクエリパラメータ】
前の例では、find関数の最初のパラメータクエリで得られたドキュメントを指定または指定しません.元のセットのドキュメントのすべてのキー値ペアが含まれます.この場合、特定のキー値は、ドキュメントのいくつかのキー値ペアにのみ関心を持つ可能性があるため、特に多くのドキュメントには適用されません.この場合、find関数の2番目のパラメータを使用して、返されるキー値のペアを指定することができます.これにより、転送されるデータ量を低減し、効率を向上させることができます.2番目のパラメータは、次の例のようにドキュメントです.
> db.people.find({},{"age":1,"name":1});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
> db.people.find({},{"age":1});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18 }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28 }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38 }
> db.people.find({},{"name":1});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "name" : "tim" }
> db.people.find({},{"name":1,"_id":0});
{ "name" : "tom" }
{ "name" : "jimmy" }
{ "name" : "tim" }
>

find関数の2番目のパラメータを使用して、このドキュメントに注意してください.
1"_id"以外のすべてのキーについて、その値は0に等しくないか(キー値ペアを問合せたいことを示す)、0に等しいか(キー値ペアを無視することを示す)、そうでない場合はエラーを報告します.
2.「_id」以外のすべてのキーについて、その値がすべて0である場合、この場合もキー「_id」が指定されている場合、キー「_id」の値は0でなければなりません.そうしないと、エラーが発生します.
3』キー「_id」に対して、値を指定しない場合、クエリ結果には必ずこのキー値ペアが含まれ、含めたくない場合は0と指定すればよい.
以上、2番目のパラメータを使用する必要がある場合、必要なキーの値が0以外のすべての数値を指定し、キー「_id」をフィルタリングする場合は「_id」というキー値が0であることを示すテクニックをまとめた.
【問合せ条件】
前述したクエリー条件は、「=」がどれだけ正確に一致しているかということです.MongoDBのクエリには、より複雑なマッチングがあることは明らかです.たとえば範囲,OR句や反逆などである.私たちはそれぞれ紹介します.
「$lt」、「$lte」、「$gt」、「$gte」は、<、<=、>、>=に対応するすべての範囲比較オペレータです.これらを組み合わせて適用すると、18~30歳(含む)のすべてのユーザーをクエリーするなど、値の範囲内のドキュメントをクエリーできます.
> db.people.find({"age":{"$gte":18,"$lte":30}});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
>

この範囲クエリーオペレータは、値が数値のキーのほか、値が日付のキーの範囲マッチングにも特に便利です.例えば、登録日が2007/05/01までのユーザー情報を問い合わせると、次のように書くことができます.
> db.user.find();
{ "_id" : ObjectId("5020faf5d6acd1b2a3fb316f"), "name" : "tim", "age" : 40, "reg
istered" : ISODate("2007-03-02T16:00:00Z") }
{ "_id" : ObjectId("5020fb08d6acd1b2a3fb3170"), "name" : "tom", "age" : 29, "reg
istered" : ISODate("2009-07-02T16:00:00Z") }
{ "_id" : ObjectId("5020fb27d6acd1b2a3fb3171"), "name" : "jimmy", "age" : 18, "r
egistered" : ISODate("2009-09-02T16:00:00Z") }
> db.user.find({"registered":{"$lte":new Date("2007/05/01")}});
{ "_id" : ObjectId("5020faf5d6acd1b2a3fb316f"), "name" : "tim", "age" : 40, "reg
istered" : ISODate("2007-03-02T16:00:00Z") }
>

キーが値に等しくないドキュメントをクエリーする必要がある場合があります.この条件オペレータ「$ne」を使用して、等しくないことを示します.登録ユーザー名がtomに等しくないドキュメントを問い合わせるには、次の手順に従います.
> db.user.find({"name":{"$ne":"tom"}});
{ "_id" : ObjectId("5020faf5d6acd1b2a3fb316f"), "name" : "tim", "age" : 40, "reg
istered" : ISODate("2007-03-02T16:00:00Z") }
{ "_id" : ObjectId("5020fb27d6acd1b2a3fb3171"), "name" : "jimmy", "age" : 18, "r
egistered" : ISODate("2009-09-02T16:00:00Z") }
>

条件オペレータ'$ne'は、すべてのタイプの値に適しています.
【OR照会】
MongoDBにはORクエリの2つの方法があります.「$in」は1つのキーの複数の値をクエリするために使用でき、「$or」はより一般的で、複数のキー値ペアの組合せを完了するために使用できます.賞券番号が10,20,30のすべての賭け者の名前を調べることもできます.
> db.raffle.find({})
{ "_id" : ObjectId("50210091d6acd1b2a3fb3172"), "name" : "tim", "ticket_no" : 11 }
{ "_id" : ObjectId("5021009bd6acd1b2a3fb3173"), "name" : "tom", "ticket_no" : 20 }
{ "_id" : ObjectId("502100a8d6acd1b2a3fb3174"), "name" : "jimmy", "ticket_no" : 30 }
> db.raffle.find({"ticket_no":{"$in":[10,20,30]}}, {"name":1})
{ "_id" : ObjectId("5021009bd6acd1b2a3fb3173"), "name" : "tom" }
{ "_id" : ObjectId("502100a8d6acd1b2a3fb3174"), "name" : "jimmy" }
>

しかし、10,20,30または賭け者の名前が「tim」のすべての賭け情報を検索するように要求される場合は、単純に「$in」を使用することはできません.オペレータ「$or」を使用することができます.「$or」オペレータは、「$in」のような他のオペレータを組み合わせることができます.
> db.raffle.find({})
{ "_id" : ObjectId("50210091d6acd1b2a3fb3172"), "name" : "tim", "ticket_no" : 11 }
{ "_id" : ObjectId("5021009bd6acd1b2a3fb3173"), "name" : "tom", "ticket_no" : 20 }
{ "_id" : ObjectId("502100a8d6acd1b2a3fb3174"), "name" : "jimmy", "ticket_no" : 30 }
> db.raffle.find({"$or":[{"ticket_no":{"$in":[10,20,30]}},{"name":"tim"}]});
{ "_id" : ObjectId("50210091d6acd1b2a3fb3172"), "name" : "tim", "ticket_no" : 11 }
{ "_id" : ObjectId("5021009bd6acd1b2a3fb3173"), "name" : "tom", "ticket_no" : 20 }
{ "_id" : ObjectId("502100a8d6acd1b2a3fb3174"), "name" : "jimmy", "ticket_no" : 30 }
>

「$or」オペレータを使用します.値は条件配列で、配列内の各条件は最後にorで結合されます.この条件オペレータを使用するには、ドキュメントのマッチング速度を速めるために、最もゆとりのある条件を前に置くのがベストです.
【$modと$not】
$modオペレータは、フォーマットが{「キー」:{「$mod」:[num 1,num 2]}}を使用して、「キー」の値をクエリーしてnum 1に残りを取り、この値がnum 2に等しい場合、ドキュメント全体が条件に合致します.本命の年にいるすべてのユーザー(年齢は12の整数倍)を検索するには、次の手順に従います.
> db.people.find();
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
> db.people.find({"age":{"$mod":[12,0]}});
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
>

$notはメタ条件子です.つまり、他の条件に使用できるか、逆を取るか、または上記の例を示すか、今回は、本命年ではないすべてのユーザードキュメント情報を調べます.
> db.people.find();
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
> db.people.find({"age":{"$not":{"$mod":[12,0]}}});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
>

$not条件子は正規表現と組み合わせて非常に強力に使用されています.ここでは、正規表現を導入したクエリーについて説明します.
【タイプ固有のクエリー】
nullの値を持つドキュメントを検索すると、まず例を見てみましょう.
> db.cc.find();
{ "_id" : ObjectId("50210861d6acd1b2a3fb3176"), "x" : 0, "y" : null }
{ "_id" : ObjectId("50210867d6acd1b2a3fb3177"), "x" : 0, "y" : 1 }
{ "_id" : ObjectId("5021086ad6acd1b2a3fb3178"), "x" : 0, "y" : 2 }
> db.cc.find({"y":null});
{ "_id" : ObjectId("50210861d6acd1b2a3fb3176"), "x" : 0, "y" : null }
>

nullの条件を使用すると、正しいドキュメントをクエリーできますが、キーyのないドキュメントがコレクションに存在する場合、どのような状況が発生するかは無視されます.
> db.cc.find();
{ "_id" : ObjectId("50210861d6acd1b2a3fb3176"), "x" : 0, "y" : null }
{ "_id" : ObjectId("50210867d6acd1b2a3fb3177"), "x" : 0, "y" : 1 }
{ "_id" : ObjectId("5021086ad6acd1b2a3fb3178"), "x" : 0, "y" : 2 }
{ "_id" : ObjectId("5021097ed6acd1b2a3fb3179"), "x" : 0 }
> db.cc.find({"y":null});
{ "_id" : ObjectId("50210861d6acd1b2a3fb3176"), "x" : 0, "y" : null }
{ "_id" : ObjectId("5021097ed6acd1b2a3fb3179"), "x" : 0 }
>

案の定、このキーがないドキュメントはnullと同じ一致値です.このドキュメントをフィルタリングする必要がある場合は、このキーが存在する必要があることを示す別の条件オペレータ$existsが必要です.
> db.cc.find();
{ "_id" : ObjectId("50210861d6acd1b2a3fb3176"), "x" : 0, "y" : null }
{ "_id" : ObjectId("50210867d6acd1b2a3fb3177"), "x" : 0, "y" : 1 }
{ "_id" : ObjectId("5021086ad6acd1b2a3fb3178"), "x" : 0, "y" : 2 }
{ "_id" : ObjectId("5021097ed6acd1b2a3fb3179"), "x" : 0 }
> db.cc.find({"y":{"$in":[null],$exists:true}});
{ "_id" : ObjectId("50210861d6acd1b2a3fb3176"), "x" : 0, "y" : null }
>

MongoDBには「$eq」のような等しい条件オペレータが提供されていないため,「=null」の判断は{「$in」:[null]}でしか実現できないことが分かった.
【正規表現】
正規表現はどの言語でも文字列を操作する大きな利器です.MongoDBのクエリでは、その威力は衰えません.正規表現は、文字列タイプの値に柔軟に一致します.「joy」で始まる名前と大文字小文字を無視したすべてのユーザードキュメントをクエリーするには、次の手順に従います.
> db.people.find();
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
{ "_id" : ObjectId("50210c32d6acd1b2a3fb317a"), "age" : 19, "name" : "Joe" }
{ "_id" : ObjectId("50210c3cd6acd1b2a3fb317b"), "age" : 29, "name" : "JoE" }
{ "_id" : ObjectId("50210c40d6acd1b2a3fb317c"), "age" : 29, "name" : "JoEy" }
> db.people.find({"name":/joe.*/i});
{ "_id" : ObjectId("50210c32d6acd1b2a3fb317a"), "age" : 19, "name" : "Joe" }
{ "_id" : ObjectId("50210c3cd6acd1b2a3fb317b"), "age" : 29, "name" : "JoE" }
{ "_id" : ObjectId("50210c40d6acd1b2a3fb317c"), "age" : 29, "name" : "JoEy" }
>

Shellで正規表現を書く方法はJavaScriptと一致しており、一対の「//」の間に書かれているのが正規表現です.具体的な正規表現のいくつかの書き方は、正規表現の関連規範を参照することができます.オペレータ$notと正規表現の組み合わせについて説明しましたが、ここでは以下の例を示します.
> db.people.find();
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
{ "_id" : ObjectId("50210c32d6acd1b2a3fb317a"), "age" : 19, "name" : "Joe" }
{ "_id" : ObjectId("50210c3cd6acd1b2a3fb317b"), "age" : 29, "name" : "JoE" }
{ "_id" : ObjectId("50210c40d6acd1b2a3fb317c"), "age" : 29, "name" : "JoEy" }
> db.people.find({"name":{"$not":/joe.*/i}});
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
>

$notを使用することは、この正規表現と一致しないことを示す正規表現としてのキーであることがわかります.前述したように、MongoDBは正規表現というデータ型をサポートしています.すなわち、「キー値ペア」では「値」を正規表現にすることができます.このキー値ペアでは、正規表現も一致します.
> db.people.find();
{ "_id" : ObjectId("501dffc605f64f64b0765c53"), "age" : 18, "name" : "tom" }
{ "_id" : ObjectId("501dffcc05f64f64b0765c54"), "age" : 28, "name" : "jimmy" }
{ "_id" : ObjectId("501dffd005f64f64b0765c55"), "age" : 38, "name" : "tim" }
{ "_id" : ObjectId("50210579d6acd1b2a3fb3175"), "age" : 36, "name" : "cliff" }
{ "_id" : ObjectId("50210c32d6acd1b2a3fb317a"), "age" : 19, "name" : "Joe" }
{ "_id" : ObjectId("50210c3cd6acd1b2a3fb317b"), "age" : 29, "name" : "JoE" }
{ "_id" : ObjectId("50210c40d6acd1b2a3fb317c"), "age" : 29, "name" : "JoEy" }
{ "_id" : ObjectId("50210f63d6acd1b2a3fb317d"), "age" : 99, "name" : /joe/i }
> db.people.find({"name":/joe/i});
{ "_id" : ObjectId("50210c32d6acd1b2a3fb317a"), "age" : 19, "name" : "Joe" }
{ "_id" : ObjectId("50210c3cd6acd1b2a3fb317b"), "age" : 29, "name" : "JoE" }
{ "_id" : ObjectId("50210c40d6acd1b2a3fb317c"), "age" : 29, "name" : "JoEy" }
{ "_id" : ObjectId("50210f63d6acd1b2a3fb317d"), "age" : 99, "name" : /joe/i }
>

しかし、正規表現のマッチングは完全なマッチングでなければならないことに注意してください.すなわち、正規表現の書き方が完全に同じでなければマッチングに成功しません(これは実際の応用ではほとんど遭遇しません).
MongoDBは、接頭辞型の正規表現(/^joe/i)クエリにインデックスを使用できるので、このような接頭辞型の正規表式クエリの速度が速い!
ここではfind関数とfindOne関数の違いを少し説明します.さっき言ったように、find関数はサブセットを返しますが、findOneはドキュメントまたはnull(結果がクエリーされていません)を返し、ドキュメントをパラメータとして受け入れる関数、例えばinsertについてはfindOneの戻り値をパラメータとして直接使用することができます.
最後に、この基本的なクエリー条件オペレータの部分についてまとめます.モディファイヤオペレータも「$set」、「$inc」などの「$」で始まるので、ここで説明したクエリー条件オペレータも「$」で始まるので、どのような違いがありますか.モディファイヤオペレータは外層ドキュメントのキーですが、クエリー条件のオペレータは基本的に内層ドキュメントのキーです($orは例外です).