著者は、 Open Internet / Free Speech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

MongoDB は、ドキュメント形式のデータを保存および処理するために使用される永続的なドキュメント指向データベースです。 他のデータベース管理システムと同様に、MongoDBでは、次の4つの基本的なタイプのデータ操作を通じてデータを管理および操作できます。

  • Create操作。データベースへのデータの書き込みが含まれます。
  • Read操作。データベースにクエリを実行してデータベースからデータを取得します。
  • Update操作。データベースにすでに存在するデータを変更します
  • Delete操作。データベースからデータを完全に削除します。

これらの4つの操作は、まとめてCRUD操作と呼ばれます。

このチュートリアルでは、新しいMongoDBドキュメントを作成し、後でそれらを取得してデータを読み取る方法の概要を説明します。 また、ドキュメント内のデータを更新する方法、およびドキュメントが不要になったときにドキュメントを削除する方法についても説明します。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • sudo権限を持つ通常の非rootユーザーと、UFWで構成されたファイアウォールを備えたサーバー。 このチュートリアルは、Ubuntu 20.04を実行しているサーバーを使用して検証されており、Ubuntu20.04のこの初期サーバーセットアップチュートリアルに従ってサーバーを準備できます。
  • サーバーにインストールされているMongoDB。 これを設定するには、 Ubuntu20.04にMongoDBをインストールする方法に関するチュートリアルに従ってください。
  • 認証を有効にして管理ユーザーを作成することにより、サーバーのMongoDBインスタンスを保護します。 このようにMongoDBを保護するには、 Ubuntu20.04でMongoDBを保護する方法に関するチュートリアルに従ってください。
  • このチュートリアル全体で使用されるMongoDBシェルの基本的な知識。 MongoDBシェルの使用方法については、チュートリアル MongoDBShellの使用方法に従ってください。

注:サーバーの構成、インストール、およびMongoDBの安全なインストールの方法に関するリンクされたチュートリアルは、Ubuntu20.04を参照しています。 このチュートリアルは、基盤となるオペレーティングシステムではなく、MongoDB自体に焦点を当てています。 通常、認証が有効になっている限り、オペレーティングシステムに関係なく、すべてのMongoDBインストールで機能します。

ステップ1—MongoDBサーバーに接続する

このガイドでは、MongoDBシェルを使用してMongoDBと対話します。 MongoDBでCRUD操作を実行して実行するには、最初にMongoDBシェルを開いてMongoDBデータベースに接続する必要があります。

MongoDBインスタンスがリモートサーバーで実行されている場合は、ローカルマシンからそのサーバーにSSHで接続します。

  1. ssh sammy@your_server_ip

次に、MongoDBシェルを開いて、MongoDBインストールに接続します。 データの書き込みと読み取りの権限を持つMongoDBユーザーとして接続してください。 前提条件のMongoDBセキュリティチュートリアルに従った場合、そのガイドのステップ1で作成した管理ユーザーとして接続できます。

  1. mongo -u AdminSammy -p --authenticationDatabase admin

ユーザーのパスワードを入力すると、端末プロンプトが大なり記号(>)に変わります。 これは、シェルが接続先のMongoDBサーバーのコマンドを受け入れる準備ができたことを意味します。

注:新しい接続では、MongoDBシェルはデフォルトでtestデータベースに自動的に接続します。 このデータベースを安全に使用して、MongoDBとMongoDBシェルを試すことができます。

または、別のデータベースに切り替えて、このチュートリアルに記載されているすべてのコマンド例を実行することもできます。 別のデータベースに切り替えるには、useコマンドに続けて、データベースの名前を実行します。

  1. use database_name

MongoDBシェルを使用してMongoDBサーバーに接続したので、新しいドキュメントの作成に進むことができます。

ステップ2—ドキュメントの作成

このガイドの後のステップで読み取り、更新、および削除を練習できるデータを用意するために、このステップでは、MongoDBでデータドキュメントを作成する方法に焦点を当てます。

MongoDBを使用して、世界中の有名な歴史的建造物のディレクトリを構築および管理していると想像してみてください。 このディレクトリには、各記念碑の名前、国、都市、地理的な場所などの情報が保存されます。

このディレクトリ内のドキュメントは、ギザのピラミッドを表すこの例と同様の形式に従います。

ギザのピラミッド
{
    "name": "The Pyramids of Giza",
    "city": "Giza",
    "country": "Egypt",
    "gps": {
        "lat": 29.976480,
        "lng": 31.131302
    }
}

このドキュメントは、すべてのMongoDBドキュメントと同様に、BSONで記述されています。 BSONは、人間が読める形式のJSONのバイナリ形式です。 BSONまたはJSONドキュメントのすべてのデータは、field: valueの形式をとるフィールドと値のペアとして表されます。

このドキュメントは4つのフィールドで構成されています。 最初は記念碑の名前で、次に都市と国が続きます。 これらの3つのフィールドすべてに文字列が含まれています。 gpsと呼ばれる最後のフィールドは、記念碑のGPS位置を詳細に示すネストされたドキュメントです。 この場所は、緯度と経度の座標のペアで構成され、それぞれlatフィールドとlngフィールドで表され、それぞれが浮動小数点値を保持します。

注: MongoDBドキュメントの構造について詳しくは、概念記事ドキュメント指向データベースの概要をご覧ください。

insertOneメソッドを使用して、このドキュメントをmonumentsという新しいコレクションに挿入します。 その名前が示すように、insertOneは、一度に複数のドキュメントを作成するのではなく、個々のドキュメントを作成するために使用されます。

MongoDBシェルで、次の操作を実行します。

  1. db.monuments.insertOne(
  2. {
  3. "name": "The Pyramids of Giza",
  4. "city": "Giza",
  5. "country": "Egypt",
  6. "gps": {
  7. "lat": 29.976480,
  8. "lng": 31.131302
  9. }
  10. }
  11. )

このinsertOneメソッドを実行する前に、monumentsコレクションを明示的に作成していないことに注意してください。 MongoDBを使用すると、存在しないコレクションに対してコマンドを自由に実行できます。欠落しているコレクションは、最初のオブジェクトが挿入されたときにのみ作成されます。 この例のinsertOne()メソッドを実行すると、ドキュメントがコレクションに挿入されるだけでなく、コレクションが自動的に作成されます。

MongoDBは、insertOneメソッドを実行し、ギザのピラミッドを表す要求されたドキュメントを挿入します。 操作の出力は、正常に実行されたことを通知し、新しいドキュメント用に自動的に生成されたObjectIdも提供します。

Output
{ "acknowledged" : true, "insertedId" : ObjectId("6105752352e6d1ebb7072647") }

MongoDBでは、コレクション内の各ドキュメントには、主キーとして機能する一意の_idフィールドが必要です。 _idフィールドを含めて、各ドキュメントの_idフィールドが一意であることを確認する限り、独自に選択した値を指定できます。 ただし、新しいドキュメントで_idフィールドが省略されている場合、MongoDBは_idフィールドの値としてオブジェクト識別子(ObjectIdオブジェクトの形式)を自動的に生成します。

monumentsコレクションのオブジェクト数を確認することで、ドキュメントが挿入されたことを確認できます。

  1. db.monuments.count()

このコレクションに挿入したドキュメントは1つだけなので、countメソッドは1を返します。

Output
1

このようにドキュメントを1つずつ挿入すると、複数のドキュメントを作成する場合にすぐに面倒になります。 MongoDBは、1回の操作で複数のドキュメントを挿入するために使用できるinsertManyメソッドを提供します。

次のコマンド例を実行します。このコマンドは、insertManyメソッドを使用して、6つの有名なモニュメントをmonumentsコレクションに挿入します。

  1. db.monuments.insertMany([
  2. {"name": "The Valley of the Kings", "city": "Luxor", "country": "Egypt", "gps": { "lat": 25.746424, "lng": 32.605309 }},
  3. {"name": "Arc de Triomphe", "city": "Paris", "country": "France", "gps": { "lat": 48.873756, "lng": 2.294946 }},
  4. {"name": "The Eiffel Tower", "city": "Paris", "country": "France", "gps": { "lat": 48.858093, "lng": 2.294694 }},
  5. {"name": "Acropolis", "city": "Athens", "country": "Greece", "gps": { "lat": 37.970833, "lng": 23.726110 }},
  6. {"name": "The Great Wall of China", "city": "Huairou", "country": "China", "gps": { "lat": 40.431908, "lng": 116.570374 }},
  7. {"name": "The Statue of Liberty", "city": "New York", "country": "USA", "gps": { "lat": 40.689247, "lng": -74.044502 }}
  8. ])

6つのドキュメントを囲む角かっこ([および])に注意してください。 これらの括弧は、ドキュメントの配列を示します。 角かっこ内には、コンマで区切られた複数のオブジェクトが次々に表示されます。 MongoDBメソッドが複数のオブジェクトを必要とする場合は、このような配列の形式でオブジェクトのリストを提供できます。

MongoDBは、新しく挿入されたオブジェクトごとに1つずつ、いくつかのオブジェクト識別子で応答します。

Output
{ "acknowledged" : true, "insertedIds" : [ ObjectId("6105770952e6d1ebb7072648"), ObjectId("6105770952e6d1ebb7072649"), ObjectId("6105770952e6d1ebb707264a"), ObjectId("6105770952e6d1ebb707264b"), ObjectId("6105770952e6d1ebb707264c"), ObjectId("6105770952e6d1ebb707264d") ] }

monumentsコレクションのオブジェクト数を確認することで、ドキュメントが挿入されたことを確認できます。

  1. db.monuments.count()

これらの6つの新しいドキュメントを追加した後、このコマンドの期待される出力は7です。

Output
7

これで、2つの別々の挿入方法を使用して、いくつかの有名なモニュメントを表す多数のドキュメントを作成しました。 次に、MongoDBのfind()メソッドで挿入したデータを読み取ります。

ステップ3—ドキュメントを読む

コレクションにいくつかのドキュメントが保存されたので、データベースにクエリを実行してこれらのドキュメントを取得し、データを読み取ることができます。 この手順では、最初に特定のコレクション内のすべてのドキュメントをクエリする方法の概要を説明し、次にフィルターを使用して取得したドキュメントのリストを絞り込む方法について説明します。

前の手順を完了すると、monumentsコレクションに挿入された有名なモニュメントを説明する7つのドキュメントが作成されます。 find()メソッドを使用すると、1回の操作で7つのドキュメントすべてを取得できます。

  1. db.monuments.find()

このメソッドを引数なしで使用すると、フィルタリングは適用されず、MongoDBに、指定されたコレクションmonumentsで使用可能なすべてのオブジェクトを返すように要求します。 MongoDBは次の出力を返します。

Output
{ "_id" : ObjectId("6105752352e6d1ebb7072647"), "name" : "The Pyramids of Giza", "city" : "Giza", "country" : "Egypt", "gps" : { "lat" : 29.97648, "lng" : 31.131302 } } { "_id" : ObjectId("6105770952e6d1ebb7072648"), "name" : "The Valley of the Kings", "city" : "Luxor", "country" : "Egypt", "gps" : { "lat" : 25.746424, "lng" : 32.605309 } } { "_id" : ObjectId("6105770952e6d1ebb7072649"), "name" : "Arc de Triomphe", "city" : "Paris", "country" : "France", "gps" : { "lat" : 48.873756, "lng" : 2.294946 } } { "_id" : ObjectId("6105770952e6d1ebb707264a"), "name" : "The Eiffel Tower", "city" : "Paris", "country" : "France", "gps" : { "lat" : 48.858093, "lng" : 2.294694 } } { "_id" : ObjectId("6105770952e6d1ebb707264b"), "name" : "Acropolis", "city" : "Athens", "country" : "Greece", "gps" : { "lat" : 37.970833, "lng" : 23.72611 } } { "_id" : ObjectId("6105770952e6d1ebb707264c"), "name" : "The Great Wall of China", "city" : "Huairou", "country" : "China", "gps" : { "lat" : 40.431908, "lng" : 116.570374 } } { "_id" : ObjectId("6105770952e6d1ebb707264d"), "name" : "The Statue of Liberty", "city" : "New York", "country" : "USA", "gps" : { "lat" : 40.689247, "lng" : -74.044502 } }

MongoDBシェルは、7つのドキュメントすべてを1つずつ完全に出力します。 これらの各オブジェクトには、定義していない_idプロパティがあることに注意してください。 前述のように、_idフィールドはそれぞれのドキュメントの主キーとして機能し、前の手順でinsertManyメソッドを実行したときに自動的に作成されました。

MongoDBシェルからのデフォルトの出力はコンパクトで、各ドキュメントのフィールドと値が1行に出力されます。 これは、特に複数のフィールドまたはネストされたドキュメントを含むオブジェクトでは読みにくくなる可能性があります。

find()メソッドの出力を読みやすくするために、次のようなpretty印刷機能を使用できます。

  1. db.monuments.find().pretty()

今回は、MongoDBシェルがドキュメントを複数行に印刷し、それぞれにインデントを付けます。

Output
{ "_id" : ObjectId("6105752352e6d1ebb7072647"), "name" : "The Pyramids of Giza", "city" : "Giza", "country" : "Egypt", "gps" : { "lat" : 29.97648, "lng" : 31.131302 } } { "_id" : ObjectId("6105770952e6d1ebb7072648"), "name" : "The Valley of the Kings", "city" : "Luxor", "country" : "Egypt", "gps" : { "lat" : 25.746424, "lng" : 32.605309 } } . . .

前の2つの例では、find()メソッドが引数なしで実行されたことに注意してください。 どちらの場合も、コレクションからすべてのオブジェクトを返しました。 クエリにフィルタを適用して、結果を絞り込むことができます。

前の例から、MongoDBが王家の谷ObjectId("6105770952e6d1ebb7072648")の値を持つオブジェクト識別子を自動的に割り当てたことを思い出してください。 オブジェクト識別子は、ObjectId("")内の16進文字列だけでなく、ObjectIdオブジェクト全体(オブジェクト識別子を格納するためにMongoDBで使用される特別なデータ型)です。

次のfind()メソッドは、クエリフィルタードキュメントを引数として受け入れることにより、単一のオブジェクトを返します。 クエリフィルタードキュメントは、コレクションに挿入するドキュメントと同じ構造に従い、フィールドと値で構成されますが、代わりにクエリ結果のフィルターに使用されます。

この例で使用されているクエリフィルタードキュメントには、_idフィールドが含まれており、値として The Valley of theKings’オブジェクト識別子が含まれています。 独自のデータベースでこのクエリを実行するには、強調表示されたオブジェクト識別子を、独自のmonumentsコレクションに保存されているドキュメントの1つに置き換えてください。

  1. db.monuments.find({"_id": ObjectId("6105770952e6d1ebb7072648")}).pretty()

この例のクエリフィルタードキュメントは、等式条件を使用します。つまり、クエリは、ドキュメントで指定されたものと一致するフィールドと値のペアを持つすべてのドキュメントを返します。 基本的に、この例では、find()メソッドに、_idの値がObjectId("6105770952e6d1ebb7072648")と等しいドキュメントのみを返すように指示しています。

このメソッドを実行した後、MongoDBは要求されたオブジェクト識別子に一致する単一のオブジェクトを返します。

Output
{ "_id" : ObjectId("6105770952e6d1ebb7072648"), "name" : "The Valley of the Kings", "city" : "Luxor", "country" : "Egypt", "gps" : { "lat" : 25.746424, "lng" : 32.605309 } }

ドキュメントの他のフィールドでも品質条件を使用できます。 説明のために、フランスで記念碑を検索してみてください。

  1. db.monuments.find({"country": "France"}).pretty()

このメソッドは2つのモニュメントを返します。

Output
{ "_id" : ObjectId("6105770952e6d1ebb7072649"), "name" : "Arc de Triomphe", "city" : "Paris", "country" : "France", "gps" : { "lat" : 48.873756, "lng" : 2.294946 } } { "_id" : ObjectId("6105770952e6d1ebb707264a"), "name" : "The Eiffel Tower", "city" : "Paris", "country" : "France", "gps" : { "lat" : 48.858093, "lng" : 2.294694 } }

クエリフィルタードキュメントは非常に強力で柔軟性があり、コレクションドキュメントに複雑なフィルターを適用できます。

コレクションをクエリするさまざまな方法の詳細については、クエリの作成方法チュートリアルをご覧ください。

–>

ステップ4—ドキュメントの更新

MongoDBのようなドキュメント指向データベース内のドキュメントは、時間の経過とともに変化するのが一般的です。 場合によっては、アプリケーションの要件の変化に合わせて構造を進化させる必要があります。そうしないと、データ自体が変化する可能性があります。 この手順では、個々のドキュメントのフィールド値を変更したり、コレクション内のすべてのドキュメントに新しいフィールドを追加したりして、既存のドキュメントを更新する方法に焦点を当てます。

insertOne()およびinsertMany()メソッドと同様に、MongoDBには、単一のドキュメントまたは複数のドキュメントを一度に更新できるメソッドが用意されています。 これらの更新メソッドとの重要な違いは、新しいドキュメントを作成するときに、メソッド引数としてドキュメントデータを渡すだけでよいことです。 コレクション内の既存のドキュメントを更新するには、更新するドキュメントを指定する引数も渡す必要があります。

ユーザーがこれを実行できるようにするために、MongoDBは、更新メソッドで、前の手順でドキュメントを検索および取得するために使用したものと同じクエリフィルタードキュメントメカニズムを使用します。 ドキュメントの取得に使用できるクエリフィルタードキュメントを使用して、更新するドキュメントを指定することもできます。

凱旋門の名前を凱旋門のフルネームに変更してみてください。 これを行うには、単一のドキュメントを更新するupdateOne()メソッドを使用します。

  1. db.monuments.updateOne(
  2. { "name": "Arc de Triomphe" },
  3. {
  4. $set: { "name": "Arc de Triomphe de l'Étoile" }
  5. }
  6. )

updateOneメソッドの最初の引数は、前の手順で説明したように、単一の等式条件を持つクエリフィルタードキュメントです。 この例では、{ "name": "Arc de Triomphe" }は、Arc de Triompheの値を保持するnameキーを持つドキュメントを検索します。 ここでは、任意の有効なクエリフィルタードキュメントを使用できます。

2番目の引数は更新ドキュメントであり、更新中に適用する必要がある変更を指定します。 更新ドキュメントは、キーとしての更新演算子と、値としての各演算子のパラメーターで構成されています。 この例では、使用される更新演算子は$setです。 ドキュメントフィールドを新しい値に設定する役割を果たし、新しいフィールド値を持つJSONオブジェクトが必要です。 ここで、set: { "name": "Arc de Triomphe de l'Étoile" }は、フィールドnameの値をArc de Triomphe de l'Étoileに設定するようにMongoDBに指示します。

このメソッドは、クエリフィルタードキュメントによって1つのオブジェクトが検出され、1つのオブジェクトが正常に更新されたことを示す結果を返します。

Output
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

注:ドキュメントクエリフィルターが単一のドキュメントを選択するのに十分正確でない場合、updateOne()は、複数の結果から返された最初のドキュメントのみを更新します。

更新が機能したかどうかを確認するには、Franceに関連するすべてのモニュメントを取得してみてください。

  1. db.monuments.find({"country": "France"}).pretty()

今回、このメソッドは Arc de Triomphe を返しますが、フルネームは更新操作によって変更されています。

Output
{ "_id" : ObjectId("6105770952e6d1ebb7072649"), "name" : "Arc de Triomphe de l'Étoile", "city" : "Paris", "country" : "France", "gps" : { "lat" : 48.873756, "lng" : 2.294946 } } . . .

複数のドキュメントを変更するには、代わりにupdateMany()メソッドを使用できます。

例として、誰がエントリを作成したかについての情報がないことに気づき、データベースに各記念碑を追加した作成者の功績を認めたいとします。 これを行うには、monumentsコレクションの各ドキュメントに新しいeditorフィールドを追加します。

次の例には、空のクエリフィルタードキュメントが含まれています。 空のクエリドキュメントを含めることにより、この操作はコレクション内のすべてのドキュメントに一致し、updateMany()メソッドは各ドキュメントに影響します。 更新ドキュメントは、各ドキュメントに新しいeditorフィールドを追加し、それにSammyの値を割り当てます。

  1. db.monuments.updateMany(
  2. { },
  3. {
  4. $set: { "editor": "Sammy" }
  5. }
  6. )

このメソッドは、次の出力を返します。

Output
{ "acknowledged" : true, "matchedCount" : 7, "modifiedCount" : 7 }

この出力は、7つのドキュメントが一致し、7つも変更されたことを通知します。

変更が適用されたことを確認します。

  1. db.monuments.find().pretty()
Output
{ "_id" : ObjectId("6105752352e6d1ebb7072647"), "name" : "The Pyramids of Giza", "city" : "Giza", "country" : "Egypt", "gps" : { "lat" : 29.97648, "lng" : 31.131302 }, "editor" : "Sammy" } { "_id" : ObjectId("6105770952e6d1ebb7072648"), "name" : "The Valley of the Kings", "city" : "Luxor", "country" : "Egypt", "gps" : { "lat" : 25.746424, "lng" : 32.605309 }, "editor" : "Sammy" } . . .

返されたすべてのドキュメントには、editorという新しいフィールドがSammyに設定されています。 $set更新演算子に存在しないフィールド名を指定することにより、更新操作は、一致するすべてのドキュメントに欠落しているフィールドを作成し、新しい値を適切に設定します。

$setを最も頻繁に使用しますが、MongoDBでは他の多くの更新演算子を使用できるため、ドキュメントのデータと構造に複雑な変更を加えることができます。 これらの更新演算子の詳細については、MongoDBの主題に関する公式ドキュメントを参照してください。

ステップ5—ドキュメントを削除する

データベース内のデータが古くなり、削除する必要がある場合があります。 Mongoの更新および挿入操作と同様に、クエリフィルタードキュメントと一致する最初のドキュメントのみを削除するdeleteOne()メソッドと、複数のオブジェクトを削除するdeleteMany()メソッドがあります。一度に。

これらの方法の使用を練習するには、最初に変更した凱旋門記念碑を削除してみてください。

  1. db.monuments.deleteOne(
  2. { "name": "Arc de Triomphe de l'Étoile" }
  3. )

このメソッドには、前の更新と取得の例のようなクエリフィルタードキュメントが含まれていることに注意してください。 以前と同様に、有効なクエリを使用して、削除するドキュメントを指定できます。

MongoDBは次の結果を返します。

Output
{ "acknowledged" : true, "deletedCount" : 1 }

ここで、結果は、プロセスで削除されたドキュメントの数を示しています。

フランスの記念碑を照会して、ドキュメントが実際にコレクションから削除されているかどうかを確認します。

  1. db.monuments.find({"country": "France"}).pretty()

今回は、凱旋門を削除したため、このメソッドは単一の記念碑エッフェル塔のみを返します。

Output
{ "_id" : ObjectId("6105770952e6d1ebb707264a"), "name" : "The Eiffel Tower", "city" : "Paris", "country" : "France", "gps" : { "lat" : 48.858093, "lng" : 2.294694 }, "editor" : "Sammy" }

複数のドキュメントを一度に削除する方法を説明するために、Sammyがエディターであったすべての記念碑ドキュメントを削除します。 以前にSammyをすべてのモニュメントのエディターとして指定したため、これによりコレクションが空になります。

  1. db.monuments.deleteMany(
  2. { "editor": "Sammy" }
  3. )

今回、MongoDBは、このメソッドが6つのドキュメントを削除したことを通知します。

Output
{ "acknowledged" : true, "deletedCount" : 6 }

monumentsコレクションが空になったことを確認するには、その中のドキュメントの数を数えます。

  1. db.monuments.count()
Output
0

コレクションからすべてのドキュメントを削除したので、このコマンドは0の期待される出力を返します。

結論

この記事を読むことで、CRUD操作の概念( C reate、 R ead、 U pdate、 D elete)に慣れました。 —データ管理の4つの重要なコンポーネント。 これで、MongoDBデータベースに新しいドキュメントを挿入したり、既存のドキュメントを変更したり、コレクションにすでに存在するドキュメントを取得したり、必要に応じてドキュメントを削除したりできます。

ただし、このチュートリアルでは、クエリフィルタリングの基本的な方法を1つだけ取り上げていることに注意してください。 MongoDBは、複雑な基準に対して関心のあるドキュメントを正確に選択できる堅牢なクエリシステムを提供します。 より複雑なクエリの作成について詳しくは、主題に関する公式のMongoDBドキュメントを確認することをお勧めします。