MongoDBでクエリを作成する方法
著者は、 Open Internet / Free Speech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
MongoDBデータベースに保存されているドキュメントは、大きく異なる可能性があります。 ショッピングリストのアイテムのように、比較的小さく、エントリが少ないものもあります。 他のものは非常に複雑で、異なるタイプの数十のフィールド、複数の値を保持する配列、さらにはより大きな構造内にネストされた他のドキュメントを含む場合があります。
ドキュメントの複雑さや数に関係なく、ほとんどの場合、すべてのドキュメントのデータを一度に確認する必要はありません。 代わりに、1つ以上の特定の条件を満たすドキュメントのみを取得することをお勧めします。 海辺からの距離、ペットにやさしい、プール、近くの駐車場など、予約Webサイトでさまざまなフィルターを選択して休暇の目的地を見つける方法と同様に、MongoDBに正確にクエリを実行して、必要なドキュメントを正確に見つけることができます。 。 MongoDBは、ドキュメントを取得するときにフィルタリング基準を定義するための堅牢なクエリメカニズムを提供します。
このチュートリアルでは、さまざまな範囲のフィルターと条件を使用してMongoDBコレクションをクエリする方法を学習します。 また、カーソルとは何か、およびMongoDBシェル内でカーソルを使用する方法についても学習します。
前提条件
このチュートリアルに従うには、次のものが必要です。
- 通常のroot以外のユーザーがいるサーバー
sudo
特権とUFWで構成されたファイアウォール。 このチュートリアルは、Ubuntu 20.04を実行しているサーバーを使用して検証されており、Ubuntu20.04のこの初期サーバーセットアップチュートリアルに従ってサーバーを準備できます。 - サーバーにインストールされているMongoDB。 これを設定するには、 Ubuntu20.04にMongoDBをインストールする方法に関するチュートリアルに従ってください。
- 認証を有効にして管理ユーザーを作成することにより、サーバーのMongoDBインスタンスを保護します。 このようにMongoDBを保護するには、 Ubuntu20.04でMongoDBを保護する方法に関するチュートリアルに従ってください。
- MongoDB CRUD操作に精通しており、特にコレクションからオブジェクトを取得している。 MongoDBシェルを使用してCRUD操作を実行する方法については、チュートリアルMongoDBでCRUD操作を実行する方法に従ってください。
注:サーバーの構成、インストール、およびMongoDBの安全なインストールの方法に関するリンクされたチュートリアルは、Ubuntu20.04を参照しています。 このチュートリアルは、基盤となるオペレーティングシステムではなく、MongoDB自体に焦点を当てています。 通常、認証が有効になっている限り、オペレーティングシステムに関係なく、すべてのMongoDBインストールで機能します。
ステップ1—サンプルデータベースの準備
MongoDBでクエリを作成する方法(複数のフィールド、ネストされたドキュメント、配列を持つドキュメントをフィルタリングする方法など)を説明するために、このガイドでは、世界で最も高い5つの山を説明するドキュメントのコレクションを含むサンプルデータベースを使用します。
このサンプルコレクションを作成するには、管理ユーザーとしてMongoDBシェルに接続します。 このチュートリアルは、前提条件 MongoDBセキュリティチュートリアルの規則に従い、この管理ユーザーの名前が AdminSammy であり、その認証データベースが admin
. 異なる場合は、次のコマンドでこれらの詳細を変更して、独自の設定を反映させてください。
- mongo -u AdminSammy -p --authenticationDatabase admin
プロンプトが表示されたら、管理ユーザーを作成したときに設定したパスワードを入力します。 パスワードを入力すると、プロンプトが大なり記号(>
) サイン:
-
注:新しい接続では、MongoDBシェルは自動的に test
デフォルトではデータベース。 このデータベースを安全に使用して、MongoDBとMongoDBシェルを試すことができます。
または、別のデータベースに切り替えて、このチュートリアルに記載されているすべてのサンプルコマンドを実行することもできます。 別のデータベースに切り替えるには、 use
コマンドの後にデータベースの名前を続けます。
- use database_name
MongoDBが複数のフィールド、ネストされたドキュメント、配列を持つドキュメントをフィルタリングする方法を理解するには、さまざまなタイプのクエリを探索できるように十分に複雑なサンプルデータが必要です。 前述のように、このガイドでは、世界で最も高い5つの山のサンプルコレクションを使用しています。
このコレクションのドキュメントは、この形式に従います。 このサンプルドキュメントでは、エベレストについて説明しています。
{
"name": "Everest",
"height": 8848,
"location": ["Nepal", "China"],
"ascents": {
"first": {
"year": 1953,
},
"first_winter": {
"year": 1980,
},
"total": 5656,
}
}
このドキュメントには、次のフィールドと値が含まれています。
name
:ピークの名前height
:ピークの標高(メートル単位)location
:山が位置する国。 このフィールドには、複数の国にある山を許可するための配列として値が格納されますascents
:このフィールドの値は別のドキュメントです。 あるドキュメントがこのように別のドキュメント内に保存されている場合、それは埋め込みまたはネストされたドキュメントと呼ばれます。 各ascents
文書は、与えられた山の成功した登りを説明しています。 具体的には、それぞれascents
ドキュメントに含まれているtotal
与えられた各ピークの成功した上昇の総数をリストするフィールド。 さらに、これらのネストされたドキュメントのそれぞれには、値がネストされたドキュメントでもある2つのフィールドが含まれています。first
:このフィールドの値は、1つのフィールドを含むネストされたドキュメントです。year
、最初の全体的に成功した上昇の年を説明しますfirst_winter
:このフィールドの値はネストされたドキュメントであり、year
フィールド、その値は、指定された山の最初の成功した冬の登りの年を表します
現在は年のみが含まれているにもかかわらず、最初の登頂がネストされたドキュメントとして表示される理由は、サミットの名前や遠征の詳細など、将来、より多くのフィールドで登頂の詳細を拡張しやすくするためです。
次を実行します insertMany()
MongoDBシェルのメソッドを使用して、という名前のコレクションを同時に作成します peaks
5つのサンプルドキュメントを挿入します。 これらの文書は、世界で最も高い5つの山頂について説明しています。
- db.peaks.insertMany([
- {
- "name": "Everest",
- "height": 8848,
- "location": ["Nepal", "China"],
- "ascents": {
- "first": {
- "year": 1953
- },
- "first_winter": {
- "year": 1980
- },
- "total": 5656
- }
- },
- {
- "name": "K2",
- "height": 8611,
- "location": ["Pakistan", "China"],
- "ascents": {
- "first": {
- "year": 1954
- },
- "first_winter": {
- "year": 1921
- },
- "total": 306
- }
- },
- {
- "name": "Kangchenjunga",
- "height": 8586,
- "location": ["Nepal", "India"],
- "ascents": {
- "first": {
- "year": 1955
- },
- "first_winter": {
- "year": 1986
- },
- "total": 283
- }
- },
- {
- "name": "Lhotse",
- "height": 8516,
- "location": ["Nepal", "China"],
- "ascents": {
- "first": {
- "year": 1956
- },
- "first_winter": {
- "year": 1988
- },
- "total": 461
- }
- },
- {
- "name": "Makalu",
- "height": 8485,
- "location": ["China", "Nepal"],
- "ascents": {
- "first": {
- "year": 1955
- },
- "first_winter": {
- "year": 2009
- },
- "total": 361
- }
- }
- ])
出力には、新しく挿入されたオブジェクトに割り当てられたオブジェクト識別子のリストが含まれます。
Output{
"acknowledged" : true,
"insertedIds" : [
ObjectId("610c23828a94efbbf0cf6004"),
ObjectId("610c23828a94efbbf0cf6005"),
ObjectId("610c23828a94efbbf0cf6006"),
ObjectId("610c23828a94efbbf0cf6007"),
ObjectId("610c23828a94efbbf0cf6008")
]
}
を実行すると、ドキュメントが正しく挿入されたことを確認できます。 find()
引数のないメソッド。追加したばかりのすべてのドキュメントを取得します。
- db.peaks.find()
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
. . .
これで、クエリを作成するためのテストデータとして機能する山のサンプルドキュメントのリストが正常に作成されました。 次に、個々のフィールドを参照する条件でクエリを実行する方法を学習します。
ステップ2—個々のフィールドのクエリ
前のステップの最後に、MongoDBを使用しました find()
からすべてのドキュメントを返すメソッド peaks
コレクション。 ただし、このようなクエリは、ドキュメントをフィルタリングせず、常に同じ結果セットを返すため、実際にはあまり役に立ちません。
結果セットに含めるためにドキュメントが順守する必要がある特定の条件を定義することにより、MongoDBでクエリ結果をフィルター処理できます。 MongoDB チュートリアルでCRUD操作を実行する方法に従っている場合は、最も基本的なフィルタリング条件である等式条件をすでに使用しています。
例として、次のクエリを実行します。このクエリは、次のようなドキュメントを返します。 name
値はに等しい Everest
:
- db.peaks.find(
- { "name": "Everest" }
- )
2行目— { "name": "Everest" }
—は query filter document であり、条件を満たすドキュメントを見つけるためにコレクションを検索するときに適用するフィルターを指定するJSONオブジェクトです。 この操作例は、MongoDBにドキュメント内のドキュメントを取得するように指示します。 peaks
そのコレクション name
値は文字列と一致します Everest
:
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
山が1つしかないため、MongoDBは単一のドキュメントを返しました。 エベレスト peaks
コレクション。
等式条件は、MongoDBがコレクション内のドキュメントと照合しようとする単一の値を指定します。 MongoDBは、比較クエリ演算子を提供します。これにより、単一のフィールドを参照する他の条件を指定できますが、完全一致を検索するよりも複雑な方法でドキュメントをフィルタリングできます。
比較演算子は、演算子自体と、ドル記号($
)、およびクエリ演算子がドキュメントのフィルタリングに使用する値。
説明のために、次のクエリを実行して、次のドキュメントを検索します。 name
値はと等しくない Everest
:
- db.peaks.find(
- { "name": { $ne: "Everest" } }
- )
今回は、クエリフィルタードキュメントに含まれています { $ne: "Everest" }
. $ne
この例では、は比較演算子であり、「等しくない」を表します。 ピーク名、 Everest
、はこの演算子の値として再び表示されます。 このクエリは、次のドキュメントを検索しているためです name
値は等しくないと Everest
、4つのドキュメントを返します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586, "location" : [ "Nepal", "India" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 1986 }, "total" : 283 } }
. . .
The $in
演算子を使用すると、配列に保持されている複数の値の1つに一致する値を持つドキュメントを返すクエリを記述できます。
次のクエリ例には、 $in
演算子、およびそのドキュメントを返します name
値はいずれかに一致します Everest
また K2
:
- db.peaks.find(
- { "name": { $in: ["Everest", "K2"] } }
- )
単一の値の代わりに、に渡される値 $in
演算子は、中括弧で囲まれた2つのピーク名の配列です。 MongoDBは、期待どおりに2つのドキュメントを返します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }
これまでの例では、 name
テキスト値のあるフィールド。 数値に基づいてドキュメントをフィルタリングすることもできます。
次のクエリ例では、次のドキュメントを検索します height
値がより大きい 8500
:
- db.peaks.find(
- { "height": { $gt: 8500 } }
- )
このクエリには、 $gt
より大きいを表す演算子。 それに値を渡すことによって 8500
、MongoDBは次のドキュメントを返します height
値が8500より大きい:
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586, "location" : [ "Nepal", "India" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 1986 }, "total" : 283 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }
MongoDBは、このセクションで概説されているものに加えて、いくつかの比較クエリ演算子を提供します。 これらの演算子の完全なリストについては、主題に関する公式ドキュメントを参照してください。
単一のドキュメントフィールドで等式条件と比較演算子を使用する方法がわかったので、1つのクエリで複数の条件を結合する方法の学習に進むことができます。
ステップ3—複数の条件を使用する
場合によっては、単一のドキュメントフィールドに基づくフィルタリングでは、対象のドキュメントを正確に選択するのに十分ではありません。 このような場合、一度に複数の条件を使用してドキュメントをフィルタリングすることができます。
MongoDBで複数の条件を接続する方法は2つあります。 1つ目は、論理AND論理積を使用して、コレクション内の all 条件に一致するドキュメントを選択するか、論理ORを使用して、リストから少なくとも1つの条件に一致するドキュメントを選択します。
MongoDBでは、クエリフィルタードキュメントで複数のフィールドを使用する場合、AND接続詞は暗黙的です。 エベレストという名前と正確な高さ8848メートルに一致する山を選択してみてください。
- db.peaks.find(
- { "name": "Everest", "height": 8848 }
- )
構文は前の手順の等式条件の例と似ていますが、今回は2つのフィールドがクエリフィルタードキュメントに表示されていることに注意してください。 MongoDBは両方のフィールドが等しいかどうかをチェックし、ドキュメントを選択するには、両方が要求された値と一致する必要があります。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
この場合、単一のドキュメントが返されますが、高さを他の数値に変更しようとすると、返されるドキュメントは両方の条件に一致する必要があるため、結果セットは空になります。 たとえば、次の例では、シェルに出力は返されません。
- db.peaks.find(
- { "name": "Everest", "height": 9000 }
- )
この暗黙のANDは、 $and
論理クエリ演算子の後に、返されたドキュメントが満たさなければならない条件のリストが続きます。 次の例は、基本的に前の例と同じクエリですが、 $and
暗黙のAND接続詞の代わりに演算子:
- db.peaks.find(
- { $and: [{"name": "Everest"}, {"height": 8848}] }
- )
今回は、 $and
クエリ演算子は、クエリフィルタードキュメント自体です。 ここで、比較演算子は、リストに表示される2つの別個の等式条件を取ります。 name
一致し、後者は height
一致します。
すべてではなく、選択した条件のいずれかに一致するドキュメントを選択するために、代わりに $or
オペレーター:
- db.peaks.find(
- { $or: [{"name": "Everest"}, {"name": "K2"}] }
- )
使用する場合 $or
演算子の場合、ドキュメントは2つの等式フィルターのいずれかを満たす必要があります。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611, "location" : [ "Pakistan", "China" ], "ascents" : { "first" : { "year" : 1954 }, "first_winter" : { "year" : 1921 }, "total" : 306 } }
この例の各条件は単一フィールドの等式条件ですが、両方とも $and
と $or
演算子には、任意の有効なクエリフィルタードキュメントを含めることができます。 ネストされたAND/OR条件リストを含めることもできます。
を使用して複数のフィルターを結合する $and
と $or
このステップで概説されている演算子は、きめ細かいクエリ結果を取得するのに非常に役立ちます。 ただし、これまでの例ではすべて、個々の値に基づいてフィルタリングするクエリフィルタドキュメントを使用しています。 次のステップでは、配列フィールドに格納されている値に対してクエリを実行する方法の概要を説明します。
ステップ4—配列値のクエリ
1つのフィールドに、配列に格納された複数の値が含まれる場合があります。 山頂の例では、 location
そのような分野です。 ネパールやインドのカンチェンジュンガのように、山は複数の国にまたがることが多いため、この分野では単一の値で十分とは限りません。
このステップでは、配列フィールドの項目に一致するクエリフィルターを作成する方法を学習します。
ネパールにある山を表すドキュメントを選択することから始めましょう。 ただし、この例では、山の1つがネパールである限り、山に複数の場所がリストされていても問題ありません。
- db.peaks.find(
- { "location": "Nepal" }
- )
このクエリは、MongoDBにドキュメントを返すように指示する等式条件を使用します。 location
valueは、指定された文字列値と完全に一致します。 Nepal
、を使用した前の例と同様 name
分野。 MongoDBは、要求された値が配列の任意の場所に表示されるすべてのドキュメントを選択します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586, "location" : [ "Nepal", "India" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 1986 }, "total" : 283 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }
このクエリでは、MongoDBはネパールが location
分野。
しかし、中国とネパールの両方にある山を見つけたい場合はどうでしょうか。 これを行うには、単一の値ではなく、フィルタードキュメントに配列を含めることができます。
- db.peaks.find(
- { "location": ["China", "Nepal"] }
- )
データベースにはネパールと中国に4つの山がありますが、このクエリで指定された順序で国がリストされているのは1つだけなので、このクエリは1つのドキュメントを返します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }
の値に注意してください location
Makaluのフィールドは、クエリのフィルタードキュメントと同じです。 このように等式条件の値として配列を指定すると、MongoDBはドキュメントを取得します。 location
フィールドは、配列内の要素の順序を含め、クエリフィルターと完全に一致します。 説明のために、クエリを再度実行しますが、中国をネパールと交換します。
- db.peaks.find(
- { "location": ["Nepal", "China"] }
- )
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }
現在、他の2つの山が返されますが、マカルは返されません。
このような等式条件を使用することは、完全一致ではなく、配列内の要素(順序に関係なく)のみを考慮する場合には役立ちません。 幸い、MongoDBでは、配列内の任意の場所に複数の配列要素を含むドキュメントを取得できます。 $all
クエリ演算子。
説明のために、次のクエリを実行します。
- db.peaks.find(
- { "location": { $all: ["China", "Nepal"] } }
- )
The $all
オペレーターは、ドキュメントが location
配列には、中国とネパールの両方が任意の順序で含まれています。 MongoDBは、1つのクエリで3つの山すべてを返します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1956 }, "first_winter" : { "year" : 1988 }, "total" : 461 } }
{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }
この手順では、クエリフィルタドキュメントで配列を使用して、単一のフィールドに複数の値を持つドキュメントを取得する方法の概要を説明しました。 ネストされたドキュメント内に保持されているデータをクエリする場合は、そのような操作に必要な特別な構文を使用する必要があります。 これを行う方法を学ぶために次のステップに進んでください。
ステップ5—ネストされたドキュメントのフィールドをクエリする
サンプルデータベースドキュメントには、 ascent
各山の初登頂に関するさまざまな詳細を保持するフィールド。 このようにして、最初の登頂、冬の登頂、および登頂の総数に関するデータが、単一のネストされたドキュメント内にきれいにグループ化されます。 この手順では、クエリを作成するときにネストされたドキュメント内のフィールドにアクセスする方法について説明します。
サンプルを確認する Everest
もう一度文書化:
{
"name": "Everest",
"height": 8848,
"location": ["Nepal", "China"],
"ascents": {
"first": {
"year": 1953,
},
"first_winter": {
"year": 1980,
},
"total": 5656,
}
}
アクセスする name
と height
単一の値がこれらのキーの下にあるため、フィールドは単純明快でした。 しかし、与えられたピークの上昇の総数を見つけたいとしましょう。 The ascents
フィールドには、内部の上昇の総数よりも多くのデータが含まれています。 あります total
フィールドですが、メインドキュメントの一部ではないため、直接アクセスする方法はありません。
この問題を解決するために、MongoDBはネストされたドキュメントのフィールドにアクセスするためのドット表記を提供します。
MongoDBのドット表記がどのように機能するかを説明するために、次のクエリを実行します。 これにより、1000回以上登ったコレクション内のすべての山が返されます。 $gt
以前に強調表示された演算子:
- db.peaks.find(
- { "ascents.total": { $gt: 1000 } }
- )
山 エベレストはコレクション内で1000を超える登山がある唯一の山であるため、そのドキュメントのみが返されます。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848, "location" : [ "Nepal", "China" ], "ascents" : { "first" : { "year" : 1953 }, "first_winter" : { "year" : 1980 }, "total" : 5656 } }
ながら { $gt: 1000 }
クエリフィルター $gt
演算子はおなじみです。このクエリがどのようにアクセスするかに注意してください。 total
に保存されているドキュメント内に保持されているフィールド ascents
分野。 ネストされたドキュメントでは、任意のフィールドへのアクセスパスは、ネストされたオブジェクト内に入るアクションを示すドットで構成されます。
そう、 ascents.total
これは、MongoDBが最初にネストされたドキュメントを開く必要があることを意味します。 ascents
フィールドはを指し、次に total
その中のフィールド。
表記は、複数のネストされたドキュメントでも機能します。
- db.peaks.find(
- { "ascents.first_winter.year": { $gt: 2000 } }
- )
このクエリは、2000年以降にのみ冬に最初に登った山を説明するドキュメントを返します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485, "location" : [ "China", "Nepal" ], "ascents" : { "first" : { "year" : 1955 }, "first_winter" : { "year" : 2009 }, "total" : 361 } }
以前のように、 ascents.first_winter.year
表記は、MongoDBが最初に ascents
フィールドにあり、そこにネストされたドキュメントを検索します。 次に、別のネストされたドキュメントに入ります。 first_winter
、そして最後にを取得します year
その中からフィールド。
ドット表記を使用して、MongoDB内のネストされたドキュメントの任意の深さにアクセスできます。
これで、ネストされたドキュメントのデータにアクセスする方法と、クエリ結果をフィルタリングする方法を十分に理解できるようになります。 クエリによって返されるフィールドのリストを制限する方法の学習に進むことができます。
ステップ6—フィールドのサブセットを返す
これまでのすべての例で、クエリを実行するたびに peaks
コレクション、MongoDBは1つ以上の完全なドキュメントを返しました。 多くの場合、必要なのはほんの一握りのフィールドからの情報だけです。 例として、データベースで山の名前だけを検索したい場合があります。
これは読みやすさだけでなく、パフォーマンスの問題でもあります。 ドキュメントのごく一部のみが必要な場合、ドキュメントオブジェクト全体を取得すると、データベースのパフォーマンスが不必要に低下します。 これは、このチュートリアルの例のように小さなデータセットを操作する場合は問題にならないかもしれませんが、多くの大きくて複雑なドキュメントを操作する場合は重要な考慮事項になります。
例として、に保存されている山の名前だけに関心があるとします。 peaks
コレクションですが、今回は上昇の詳細や場所は重要ではありません。 Projection を使用してクエリフィルタードキュメントを追跡することにより、クエリが返すフィールドを制限できます。
プロジェクションドキュメントは、キーがクエリされたドキュメントのフィールドに対応するJSONオブジェクトです。 投影は、包含投影または除外投影のいずれかとして構築できます。 投影ドキュメントに次のキーが含まれている場合 1
それらの値として、結果に含まれるフィールドのリストを記述します。 一方、投影キーがに設定されている場合 0
、プロジェクションドキュメントには、結果から除外されるフィールドのリストが記載されています。
次のクエリを実行します。これには、今ではおなじみのクエリが含まれています find()
方法。 このクエリの find()
メソッドには、1つではなく2つの引数が含まれています。 最初、 {}
、はクエリフィルタードキュメントです。 これは空のJSONオブジェクトです。つまり、フィルタリングは適用されません。 2番目の引数、 { "name": 1 }
、予測について説明し、クエリ結果に各ドキュメントのみが含まれることを意味します name
分野:
- db.peaks.find(
- {},
- { "name": 1 }
- )
このサンプルクエリを実行した後、MongoDBは次の結果を返します。
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest" }
{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2" }
{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga" }
{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse" }
{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu" }
返されるドキュメントは簡略化されており、 name
と _id
田畑。 MongoDBには常に _id
明示的に要求されていない場合でも、キー。
除外するフィールドを指定する方法を説明するには、次のクエリを実行します。 各ドキュメントからデータを返しますが、 ascents
と location
田畑:
- db.peaks.find(
- {},
- { "ascents": 0, "location": 0 }
- )
MongoDBは、5つの山すべてをもう一度返しますが、今回は name
, height
、 と _id
フィールドが存在します:
Output{ "_id" : ObjectId("610c23828a94efbbf0cf6004"), "name" : "Everest", "height" : 8848 }
{ "_id" : ObjectId("610c23828a94efbbf0cf6005"), "name" : "K2", "height" : 8611 }
{ "_id" : ObjectId("610c23828a94efbbf0cf6006"), "name" : "Kangchenjunga", "height" : 8586 }
{ "_id" : ObjectId("610c23828a94efbbf0cf6007"), "name" : "Lhotse", "height" : 8516 }
{ "_id" : ObjectId("610c23828a94efbbf0cf6008"), "name" : "Makalu", "height" : 8485 }
注:プロジェクションを指定する場合、包含と除外を混在させることはできません。 含めるフィールドのリスト、または除外するフィールドのリストのいずれかを指定する必要があります。
ただし、この規則には1つの例外があります。 MongoDBを使用すると、 _id
クエリに包含射影が適用されている場合でも、結果セットのフィールド。 を抑制するには _id
フィールド、追加できます "_id": 0
投影ドキュメントに。 次の例は前のクエリ例と似ていますが、以下を含むすべてのフィールドを除外します _id
、を除く name
分野:
- db.peaks.find(
- {},
- { "_id": 0, "name": 1 }
- )
Output{ "name" : "Everest" }
{ "name" : "K2" }
{ "name" : "Kangchenjunga" }
{ "name" : "Lhotse" }
{ "name" : "Makalu" }
射影を使用して、ネストされたドキュメントのフィールドを含めたり除外したりすることもできます。 たとえば、各山の最初の冬の登りと登りの総数を知りたいとします。どちらも、 ascents
分野。 さらに、各山の名前を返したいと思います。 これを行うには、次のようなクエリを実行できます。
- db.peaks.find(
- {},
- { "_id": 0, "name": 1, "ascents": { "first_winter": 1, "total": 1 } }
- )
投影がどのように指定されているかに注意してください ascents
フィールドと、それがネストされたドキュメントの構造に従い、ネストされたプロジェクション自体である方法。 を使用して "first_winter": 1, "total": 1
このクエリは、ネストされたドキュメントのこれら2つのフィールドのみを含め、他のフィールドは含めないようにデータベースに指示します。
返されるドキュメントには、要求されたフィールドのみが含まれます。
Output{ "name" : "Everest", "ascents" : { "first_winter" : { "year" : 1980 }, "total" : 5656 } }
{ "name" : "K2", "ascents" : { "first_winter" : { "year" : 1921 }, "total" : 306 } }
{ "name" : "Kangchenjunga", "ascents" : { "first_winter" : { "year" : 1988 }, "total" : 461 } }
{ "name" : "Makalu", "ascents" : { "first_winter" : { "year" : 2009 }, "total" : 361 } }
返されるドキュメントのサイズをフィールドのサブセットのみに制限すると、結果セットが読みやすくなり、パフォーマンスが向上する場合もあります。 次のステップでは、クエリによって返されるドキュメントの数を制限する方法の概要と、クエリによって返されるデータを並べ替える方法について詳しく説明します。
ステップ7—カーソルを使用してクエリ結果を並べ替えて制限する
大規模なコレクションからオブジェクトを取得する場合、結果の数を制限したり、特定の順序で並べ替えたりすることがあります。 たとえば、ショッピングサイトで人気のあるアプローチは、商品を価格で並べ替えることです。 MongoDBはcursorsを使用します。これにより、クエリ結果セットで返されるドキュメントの数を制限したり、結果を昇順または降順で並べ替えたりすることができます。
手順1のこのクエリ例を思い出してください。
- db.peaks.find()
このクエリによって返される結果セットには、各ドキュメントのすべてのデータが含まれていることを思い出してください。 peaks
コレクション。 MongoDBがからすべてのオブジェクトを返すように見えるかもしれませんが peaks
コレクション、これはそうではありません。 MongoDBが実際に返すのは、cursorオブジェクトです。
カーソルはクエリの結果セットへのポインタですが、結果セット自体ではありません。 これは反復可能なオブジェクトです。つまり、カーソルに行の次のドキュメントを返すように要求できます。そうすると、データベースからドキュメント全体が取得されます。 それが発生するまで、カーソルはリストの次のドキュメントのみを指します。
カーソルを使用すると、MongoDBは、実際のドキュメント検索が必要な場合にのみ行われるようにすることができます。 これは、問題のドキュメントが大きい場合、またはそれらの多くが一度に要求される場合に、パフォーマンスに重大な影響を与える可能性があります。
カーソルがどのように機能するかを説明するために、次の操作を実行します。 find()
と count()
メソッド:
- db.peaks.find().count()
MongoDBは次のように応答します 5
:
Output5
ボンネットの下で、 find()
メソッドはカーソルを見つけて返し、次に count()
そのカーソルでメソッドが呼び出されます。 これにより、MongoDBは、ドキュメント自体ではなく、オブジェクト数に関心があることを認識できます。 これは、ドキュメントが結果の一部にならないことを意味します—データベースが返すのはカウントだけです。 カーソルオブジェクトのメソッドを使用して、カーソルからドキュメントを取得する前にクエリをさらに変更すると、要求したデータベース操作のみがコレクションに対して実行されるようにすることができます。
注:クエリを実行すると、MongoDBシェルは返されたカーソルを自動的に20回繰り返し、最初の20件の結果を画面に表示します。 これはMongoDBシェルに固有です。 プログラムでMongoDBを操作する場合、カーソルから結果をすぐに取得することはありません。
カーソルを使用して結果セットを変更するもう1つのMongoDBメソッドは、 limit()
方法。 その名前が示すように、あなたは使用することができます limit()
クエリが返す結果の数を制限します。
コレクションから3つの山頂のみを取得する次のクエリを実行します。
- db.peaks.find(
- {},
- { "_id": 0, "name": 1, "height": 1 }
- ).limit(3)
クエリがデータをフィルタリングしていない場合でも、MongoDBシェルは5つではなく3つのオブジェクトで応答します。
Output{ "name" : "Everest", "height" : 8848 }
{ "name" : "K2", "height" : 8611 }
{ "name" : "Kangchenjunga", "height" : 8586 }
The limit(3)
カーソルに適用されたメソッドは、最初の3に達した後、それ以上のドキュメントを返すのを停止するようにカーソルに指示します。 を使用して limit()
大規模なコレクションでこのようなカーソルメソッドを使用すると、必要な結果のみを取得し、それ以上取得しないようにすることができます。
デフォルトでは、MongoDBは挿入順にオブジェクトを返しますが、その動作を変更したい場合があります。 データベースに保持されている3つの最も低い山のピークを見つけることに興味があるとします。 次のクエリを実行できます。
- db.peaks.find(
- {},
- { "_id": 0, "name": 1, "height": 1 }
- ).limit(3).sort({ "height": 1 })
追加された sort({ "height": 1 })
結果セットが前の例と異なる原因になります。
Output{ "name" : "Makalu", "height" : 8485 }
{ "name" : "Lhotse", "height" : 8516 }
{ "name" : "Kangchenjunga", "height" : 8586 }
ここでも、3つの山頂のみが返されます。 ただし、今回は最も低いものから昇順で並べ替えられています height
価値。
The sort()
カーソルのメソッドはJSONオブジェクトを受け入れます— height
—引数として、プロジェクションドキュメントと同様です。 また、並べ替えに使用されるキーのリストも受け入れます。 受け入れられる値は次のいずれかです 1
昇順または -1
各キーのソート順の降順。
結論
この記事を読むことで、MongoDBがクエリ結果をフィルタリングするために使用する方法に慣れました。 個々のフィールド、複数の条件、および配列やネストされたドキュメントなどの複雑な構造に対してコレクションドキュメントをフィルタリングしました。 また、フィールドのサブセットのみを選択し、カーソルメソッドを使用して結果を並べ替えることも学習しました。 これらの手法を使用して、他の方法では大規模なコレクションから関心のあるドキュメントのみを取得できます。
チュートリアルでは、正確なドキュメントクエリを可能にするために、MongoDBによって提案されたほんの一握りのクエリ演算子について説明しました。 公式の公式のMongoDBドキュメントを調べて、さまざまなクエリ演算子について詳しく知ることができます。