MongoDBでCRUD操作を実行する方法
序章
MongoDB は、ドキュメント形式のデータを保存および処理するために使用される永続的なドキュメント指向データベースです。 他のデータベース管理システムと同様に、MongoDBでは、次の4つの基本的なタイプのデータ操作を通じてデータを管理および操作できます。
- Create操作。データベースへのデータの書き込みが含まれます。
- Read操作。データベースにクエリを実行してデータベースからデータを取得します。
- Update操作。データベースにすでに存在するデータを変更します
- Delete操作。データベースからデータを完全に削除します。
これらの4つの操作は、まとめてCRUD操作と呼ばれます。
このチュートリアルでは、新しいMongoDBドキュメントを作成し、後でそれらを取得してデータを読み取る方法の概要を説明します。 また、ドキュメント内のデータを更新する方法、およびドキュメントが不要になったときにドキュメントを削除する方法についても説明します。
前提条件
このチュートリアルに従うには、次のものが必要です。
- 通常のroot以外のユーザーがいるサーバー
sudo
特権と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で接続します。
- ssh sammy@your_server_ip
次に、MongoDBシェルを開いて、MongoDBインストールに接続します。 データの書き込みと読み取りの権限を持つMongoDBユーザーとして接続してください。 前提条件のMongoDBセキュリティチュートリアルに従った場合、そのガイドのステップ1で作成した管理ユーザーとして接続できます。
- mongo -u AdminSammy -p --authenticationDatabase admin
ユーザーのパスワードを入力すると、ターミナルプロンプトが大なり記号に変わります(>
). これは、シェルが接続先のMongoDBサーバーのコマンドを受け入れる準備ができたことを意味します。
注:新しい接続では、MongoDBシェルは自動的に test
デフォルトではデータベース。 このデータベースを安全に使用して、MongoDBとMongoDBシェルを試すことができます。
または、別のデータベースに切り替えて、このチュートリアルに記載されているすべてのサンプルコマンドを実行することもできます。 別のデータベースに切り替えるには、 use
コマンドの後にデータベースの名前を続けます。
- 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ドキュメントの構造について詳しくは、概念記事ドキュメント指向データベースの概要をご覧ください。
このドキュメントをという新しいコレクションに挿入します monuments
を使用して insertOne
方法。 その名前が示すように、 insertOne
一度に複数のドキュメントを作成するのではなく、個々のドキュメントを作成するために使用されます。
MongoDBシェルで、次の操作を実行します。
- db.monuments.insertOne(
- {
- "name": "The Pyramids of Giza",
- "city": "Giza",
- "country": "Egypt",
- "gps": {
- "lat": 29.976480,
- "lng": 31.131302
- }
- }
- )
明示的に作成していないことに注意してください monuments
これを実行する前のコレクション insertOne
方法。 MongoDBを使用すると、存在しないコレクションに対してコマンドを自由に実行できます。欠落しているコレクションは、最初のオブジェクトが挿入されたときにのみ作成されます。 この例を実行することにより insertOne()
メソッドは、ドキュメントをコレクションに挿入するだけでなく、コレクションを自動的に作成します。
MongoDBは insertOne
メソッドを実行し、ギザのピラミッドを表す要求されたドキュメントを挿入します。 操作の出力は、正常に実行されたことを通知し、 ObjectId
新しいドキュメント用に自動的に生成されたもの:
Output{
"acknowledged" : true,
"insertedId" : ObjectId("6105752352e6d1ebb7072647")
}
MongoDBでは、コレクション内の各ドキュメントに一意のドキュメントが必要です _id
主キーとして機能するフィールド。 あなたは含めることができます _id
各ドキュメントの _id
フィールドは一意になります。 ただし、新しいドキュメントで省略されている場合 _id
フィールドの場合、MongoDBはオブジェクト識別子を自動的に生成します( ObjectId
オブジェクト)の値として _id
分野。
ドキュメントのオブジェクト数を確認することで、ドキュメントが挿入されたことを確認できます。 monuments
コレクション:
- db.monuments.count()
このコレクションに挿入したドキュメントは1つだけなので、 count
メソッドは 1
:
Output1
このようにドキュメントを1つずつ挿入すると、複数のドキュメントを作成する場合にすぐに面倒になります。 MongoDBは insertMany
1回の操作で複数のドキュメントを挿入するために使用できるメソッド。
次のコマンド例を実行します。これは、 insertMany
6つの追加の有名なモニュメントをに挿入する方法 monuments
コレクション:
- db.monuments.insertMany([
- {"name": "The Valley of the Kings", "city": "Luxor", "country": "Egypt", "gps": { "lat": 25.746424, "lng": 32.605309 }},
- {"name": "Arc de Triomphe", "city": "Paris", "country": "France", "gps": { "lat": 48.873756, "lng": 2.294946 }},
- {"name": "The Eiffel Tower", "city": "Paris", "country": "France", "gps": { "lat": 48.858093, "lng": 2.294694 }},
- {"name": "Acropolis", "city": "Athens", "country": "Greece", "gps": { "lat": 37.970833, "lng": 23.726110 }},
- {"name": "The Great Wall of China", "city": "Huairou", "country": "China", "gps": { "lat": 40.431908, "lng": 116.570374 }},
- {"name": "The Statue of Liberty", "city": "New York", "country": "USA", "gps": { "lat": 40.689247, "lng": -74.044502 }}
- ])
角かっこに注意してください([
と ]
)6つのドキュメントを囲みます。 これらの括弧は、ドキュメントの配列を示します。 角かっこ内には、コンマで区切られた複数のオブジェクトが次々に表示されます。 MongoDBメソッドが複数のオブジェクトを必要とする場合は、このような配列の形式でオブジェクトのリストを提供できます。
MongoDBは、新しく挿入されたオブジェクトごとに1つずつ、いくつかのオブジェクト識別子で応答します。
Output{
"acknowledged" : true,
"insertedIds" : [
ObjectId("6105770952e6d1ebb7072648"),
ObjectId("6105770952e6d1ebb7072649"),
ObjectId("6105770952e6d1ebb707264a"),
ObjectId("6105770952e6d1ebb707264b"),
ObjectId("6105770952e6d1ebb707264c"),
ObjectId("6105770952e6d1ebb707264d")
]
}
ドキュメントのオブジェクト数を確認することで、ドキュメントが挿入されたことを確認できます。 monuments
コレクション:
- db.monuments.count()
これらの6つの新しいドキュメントを追加した後、このコマンドの期待される出力は次のとおりです。 7
:
Output7
これで、2つの別々の挿入方法を使用して、いくつかの有名なモニュメントを表す多数のドキュメントを作成しました。 次に、MongoDBで挿入したデータを読み取ります find()
方法。
ステップ3—ドキュメントを読む
コレクションにいくつかのドキュメントが保存されたので、データベースにクエリを実行してこれらのドキュメントを取得し、データを読み取ることができます。 この手順では、最初に特定のコレクション内のすべてのドキュメントをクエリする方法の概要を説明し、次にフィルターを使用して取得したドキュメントのリストを絞り込む方法について説明します。
前の手順を完了すると、有名なモニュメントを説明する7つのドキュメントが挿入されます。 monuments
コレクション。 を使用して、1回の操作で7つのドキュメントすべてを取得できます。 find()
方法:
- 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
このような印刷機能:
- 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")
. オブジェクト識別子は、内部の16進文字列だけではありません ObjectId("")
、しかし全体 ObjectId
object —オブジェクト識別子を格納するためにMongoDBで使用される特別なデータ型。
以下 find()
メソッドは、クエリフィルタードキュメントを引数として受け入れることにより、単一のオブジェクトを返します。 クエリフィルタードキュメントは、コレクションに挿入するドキュメントと同じ構造に従い、フィールドと値で構成されますが、代わりにクエリ結果をフィルターするために使用されます。
この例で使用されているクエリフィルタードキュメントには、 _id
フィールド、王家の谷のオブジェクト識別子を値として使用します。 独自のデータベースでこのクエリを実行するには、強調表示されたオブジェクト識別子を、独自のデータベースに保存されているドキュメントの1つに置き換えてください。 monuments
コレクション:
- 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
}
}
ドキュメントの他のフィールドでも品質条件を使用できます。 説明のために、フランスで記念碑を検索してみてください。
- 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()
単一のドキュメントを更新するメソッド:
- db.monuments.updateOne(
- { "name": "Arc de Triomphe" },
- {
- $set: { "name": "Arc de Triomphe de l'Étoile" }
- }
- )
の最初の引数 updateOne
methodは、前の手順で説明したように、単一の等式条件を持つクエリフィルタードキュメントです。 この例では、 { "name": "Arc de Triomphe" }
でドキュメントを検索します name
の値を保持するキー Arc de Triomphe
. ここでは、任意の有効なクエリフィルタードキュメントを使用できます。
2番目の引数は更新ドキュメントであり、更新中に適用する必要がある変更を指定します。 更新ドキュメントは、キーとしての更新演算子と、値としての各演算子のパラメータで構成されています。 この例では、使用される更新演算子は $set
. ドキュメントフィールドを新しい値に設定する役割を果たし、新しいフィールド値を持つJSONオブジェクトが必要です。 ここ、 set: { "name": "Arc de Triomphe de l'Étoile" }
フィールドの値を設定するようにMongoDBに指示します name
に Arc de Triomphe de l'Étoile
.
このメソッドは、クエリフィルタードキュメントによって1つのオブジェクトが検出され、1つのオブジェクトが正常に更新されたことを示す結果を返します。
Output{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
注:ドキュメントクエリフィルターが単一のドキュメントを選択するのに十分な精度でない場合、 updateOne()
複数の結果から返されたfirstドキュメントのみを更新します。
更新が機能したかどうかを確認するには、に関連するすべてのモニュメントを取得してみてください France
:
- 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()
方法。
例として、誰がエントリを作成したかについての情報がないことに気づき、データベースに各記念碑を追加した作成者の功績を認めたいとします。 これを行うには、新しいを追加します editor
内の各ドキュメントへのフィールド monuments
コレクション。
次の例には、空のクエリフィルタードキュメントが含まれています。 空のクエリドキュメントを含めることにより、この操作はコレクション内のすべてのドキュメントと一致します。 updateMany()
メソッドはそれらのそれぞれに影響します。 更新ドキュメントは新しいを追加します editor
フィールドを各ドキュメントに割り当て、値を割り当てます Sammy
:
- db.monuments.updateMany(
- { },
- {
- $set: { "editor": "Sammy" }
- }
- )
このメソッドは、次の出力を返します。
Output{ "acknowledged" : true, "matchedCount" : 7, "modifiedCount" : 7 }
この出力は、7つのドキュメントが一致し、7つも変更されたことを通知します。
変更が適用されたことを確認します。
- 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()
クエリフィルタードキュメントと一致するfirstドキュメントのみを削除するメソッド。 deleteMany()
、複数のオブジェクトを一度に削除します。
これらの方法の使用を練習するには、最初に変更した凱旋門記念碑を削除してみてください。
- db.monuments.deleteOne(
- { "name": "Arc de Triomphe de l'Étoile" }
- )
このメソッドには、前の更新と取得の例のようなクエリフィルタードキュメントが含まれていることに注意してください。 以前と同様に、有効なクエリを使用して、削除するドキュメントを指定できます。
MongoDBは次の結果を返します。
Output{ "acknowledged" : true, "deletedCount" : 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
すべての記念碑の編集者として:
- db.monuments.deleteMany(
- { "editor": "Sammy" }
- )
今回、MongoDBは、このメソッドが6つのドキュメントを削除したことを通知します。
Output{ "acknowledged" : true, "deletedCount" : 6 }
次のことを確認できます monuments
コレクション内のドキュメントの数を数えることにより、コレクションは空になります。
- db.monuments.count()
Output0
コレクションからすべてのドキュメントを削除したので、このコマンドは期待される出力を返します。 0
.
結論
この記事を読むことで、CRUD操作の概念( C reate、 R ead、 U pdate、 D elete)に慣れました。 —データ管理の4つの重要なコンポーネント。 これで、MongoDBデータベースに新しいドキュメントを挿入したり、既存のドキュメントを変更したり、コレクションにすでに存在するドキュメントを取得したり、必要に応じてドキュメントを削除したりできます。
ただし、このチュートリアルでは、クエリフィルタリングの基本的な方法を1つだけ取り上げていることに注意してください。 MongoDBは、複雑な基準に対して関心のあるドキュメントを正確に選択できる堅牢なクエリシステムを提供します。 より複雑なクエリの作成について詳しくは、主題に関する公式のMongoDBドキュメントを確認することをお勧めします。