共有する

はじめに

MongoDB を使用する場合、ほとんどの時間を何らかの方法で ドキュメント の管理に費やすことになります。新しいドキュメントを作成してコレクションに追加する場合でも、ドキュメントを取得する場合でも、データを更新する場合でも、古いアイテムを削除する場合でも、ドキュメントは MongoDB モデルの中心です。

このガイドでは、MongoDB ドキュメントとは何かを説明し、ドキュメント中心の環境 を管理するために知っておくべき一般的な操作について説明します。

MongoDB ドキュメントとは?

MongoDB では、データベースとコレクション内のすべてのデータはドキュメントとして保存されます。コレクションはデフォルトで必須の スキーマ を指定しないため、コレクション内のドキュメントは任意に複雑な構造を持つことができ、兄弟ドキュメントが使用する形式と一致する必要はありません。これにより、信じられないほどの柔軟性が提供され、アプリケーション要件の変化に応じてスキーマを自然に開発できます。

MongoDB ドキュメント自体は、JSON JavaScript Object Notation のバイナリ表現である BSON データシリアライゼーション形式 を使用します。これにより、クエリやプログラムによる操作が可能な定義済みのデータ型を持つ整理された構造が提供されます。

BSON ドキュメントは、キーと値のペアを含む中括弧 ({}) で表されます。BSON では、これらのデータ対は*フィールド*とその*値*として知られています。フィールドが最初に来て、文字列で表されます。値は有効な BSON データ型 であれば何でもかまいません。コロン (:) はフィールドと値を区切ります。各フィールドと値のペアを区切るためにカンマが使用されます。

例として、MongoDB が理解できる有効な BSON ドキュメントを以下に示します。

{
_id: 80380,
vehicle_type: "car",
mileage: 7377.80,
color: "blue",
markets: [
"US",
"UK"
],
options: {
transmission: "automatic",
num_doors: 4,
power_windows: true
}
}

ここでは、かなりの数の型を見ることができます

  • _id は整数です
  • vehicle_typecolor は文字列です
  • mileage は浮動小数点数です
  • markets は文字列の配列です
  • options には、文字列、整数、ブール値で構成される値を持つネストされたドキュメントが含まれています

この柔軟性により、ドキュメントはデータを保存するための非常に柔軟な媒体となります。新しいフィールドを簡単に追加でき、ドキュメントを互いに埋め込むことができ、構造の複雑さは保存されるデータと正確に一致します。

新しいドキュメントを作成する方法

新しいドキュメントを作成するには、作成するドキュメントを保存したいデータベースに切り替えます。この記事では、デモンストレーション目的で school データベースを使用します。

use school

また、ドキュメントを挿入したいコレクションを選択します。データベースと同様に、ドキュメントを挿入したいコレクションを明示的に作成する必要はありません。MongoDB は、最初のデータが書き込まれたときに自動的に作成します。この例では、students というコレクションを使用します。

ドキュメントがどこに保存されるかがわかったので、次のいずれかの方法を使用して新しいドキュメントを挿入できます。

insert() メソッドを使用する

insert() メソッドを使用すると、呼び出されたコレクションに 1 つ以上のドキュメントを挿入できます。

単一のドキュメントを挿入するには、コレクションでメソッドを呼び出してドキュメントを渡します。ここでは、Ashley という名前の生徒の新しいドキュメントを挿入します。

db.students.insert(
{
first_name: "Ashley",
last_name: "Jenkins",
dob: new Date("January 08, 2003"),
grade_level: 8
}
)
WriteResult({ "nInserted" : 1 })

複数のドキュメントを同時に挿入したい場合は、insert() にドキュメントを渡す代わりに、ドキュメントの配列を渡します。Brian と Leah という名前の生徒の新しいドキュメントを 2 つ追加できます。

db.students.insert(
[
{
first_name: "Brian",
last_name: "McMantis",
dob: new Date("September 18, 2010"),
grade_level: 2
},
{
first_name: "Leah",
last_name: "Drake",
dob: new Date("October 03, 2009")
}
]
)
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})

バルク 書き込み操作 を実行したため、戻り値は以前に見た WriteResult オブジェクトではなく BulkWriteResult です。

insert() メソッドは柔軟ですが、多くの MongoDB ドライバーでは以下の 2 つのメソッドが推奨されるため、非推奨になっています。

insertOne() メソッドを使用する

insertOne() メソッドは、単一のドキュメントを挿入するために使用できます。insert() メソッドとは異なり、一度に 1 つのドキュメントしか挿入できないため、その動作はより予測しやすくなります。

構文は、insert() を使用して単一のドキュメントを追加する場合と同じです。Naomi という別の学生を追加できます。

db.students.insertOne(
{
first_name: "Naomi",
last_name: "Pyani"
}
)
{
"acknowledged" : true,
"insertedId" : ObjectId("60e877914655cbf49ff7cb86")
}

insert() とは異なり、insertOne() メソッドは、いくつかの追加の有用な情報を含むドキュメントを返します。書き込みがクラスターによって承認されたことを確認し、オブジェクト ID が指定されなかったため、ドキュメントに割り当てられたオブジェクト ID が含まれています。

insertMany() メソッドを使用する

一度に複数のドキュメントを挿入したいシナリオをカバーするために、現在では insertMany() メソッドが推奨されています。insert() で複数のドキュメントを挿入する場合と同様に、insertMany() はドキュメントの配列を受け取ります。

Jasmine、Michael、Toni という 3 人の新しい生徒を追加できます。

db.students.insertMany(
[
{
first_name: "Jasmine",
last_name: "Took",
dob: new Date("April 11, 2011")
},
{
first_name: "Michael",
last_name: "Rodgers",
dob: new Date("February 25, 2008"),
grade_level: 6
},
{
first_name: "Toni",
last_name: "Fowler"
}
]
)
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60e8792d4655cbf49ff7cb87"),
ObjectId("60e8792d4655cbf49ff7cb88"),
ObjectId("60e8792d4655cbf49ff7cb89")
]
}

insertOne() と同様に、insertMany() は書き込みを承認し、挿入されたドキュメントに割り当てられた ID を含む配列を提供するドキュメントを返します。

既存のドキュメントをクエリする方法

ドキュメントのクエリは非常に広範なトピックであり、独自の記事が必要です。さまざまな種類のドキュメントを取得するためのクエリの作成方法については、MongoDB 内のデータのクエリに関するガイドで詳細を確認できます。

詳細は上記のリンクされた記事に譲るとして、MongoDB がドキュメントをクエリするために提供するメソッドについて少なくとも説明できます。MongoDB からドキュメントをフェッチする主な方法は、対象のコレクションで find() メソッドを呼び出すことです。

たとえば、students からすべてのドキュメントを収集するには、引数なしで find() を呼び出すことができます。

db.students.find()
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }
{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }
{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }

出力をより読みやすくするために、find() の後に pretty() メソッドを連結することもできます。

db.<collection>.find().pretty()
{
"_id" : ObjectId("60e8743b4655cbf49ff7cb83"),
"first_name" : "Ashley",
"last_name" : "Jenkins",
"dob" : ISODate("2003-01-08T00:00:00Z"),
"grade_level" : 8
}
{
"_id" : ObjectId("60e875d54655cbf49ff7cb84"),
"first_name" : "Brian",
"last_name" : "McMantis",
"dob" : ISODate("2010-09-18T00:00:00Z"),
"grade_level" : 2
}
{
"_id" : ObjectId("60e875d54655cbf49ff7cb85"),
"first_name" : "Leah",
"last_name" : "Drake",
"dob" : ISODate("2009-10-03T00:00:00Z")
}
{
"_id" : ObjectId("60e877914655cbf49ff7cb86"),
"first_name" : "Naomi",
"last_name" : "Pyani"
}
{
"_id" : ObjectId("60e8792d4655cbf49ff7cb87"),
"first_name" : "Jasmine",
"last_name" : "Took",
"dob" : ISODate("2011-04-11T00:00:00Z")
}
{
"_id" : ObjectId("60e8792d4655cbf49ff7cb88"),
"first_name" : "Michael",
"last_name" : "Rodgers",
"dob" : ISODate("2008-02-25T00:00:00Z"),
"grade_level" : 6
}
{
"_id" : ObjectId("60e8792d4655cbf49ff7cb89"),
"first_name" : "Toni",
"last_name" : "Fowler"
}

各ドキュメントに _id フィールドが追加されていることがわかります。MongoDB では、コレクション内の各ドキュメントに一意の _id が必要です。オブジェクト作成時に指定しない場合、自動的に追加されます。この ID を使用して、単一のオブジェクトを確実に取得できます。

db.students.find(
{
_id : ObjectId("60e8792d4655cbf49ff7cb89")
}
)
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }

上記のリンクされた記事で、さまざまなデータのクエリ方法について詳しく知ることができます。

既存のドキュメントを更新する方法

データベースの多くの、またはほとんどのユースケースでは、データベース内の既存のデータを変更できる必要があります。フィールドを新しい値を反映するように更新する必要がある場合や、既存のドキュメントに追加情報が利用可能になったときにそれを追加する必要がある場合があります。

MongoDB は、既存のドキュメントを更新するためにいくつかの関連メソッドを使用します。

  • updateOne(): 指定されたフィルターに基づいて、コレクション内の単一のドキュメントを更新します。
  • updateMany(): 指定されたフィルターに一致するコレクション内の複数のドキュメントを更新します。
  • replaceOne(): 指定されたフィルターに基づいて、コレクション内のドキュメント全体を置き換えます。

これらの各種類を使用して、さまざまな種類の更新を実行する方法について説明します。

更新オペレーター

ドキュメントを更新するための各メソッドを見る前に、利用可能な更新オペレーターについて説明する必要があります。

  • $currentDate: フィールドの値を現在の日付に設定します(日付型またはタイムスタンプ型のいずれか)。
    • 構文: { $currentDate: { <field>: <type>, ... } }
  • $inc: フィールドの値を指定された量だけインクリメントします。
    • 構文: { $inc: { <field>: <amount>, ... } }
  • $min: 指定された値が現在の値よりも小さい場合、フィールドの値を更新します。
    • 構文: { $min: { <field>: <value>, ... } }
  • $max: 指定された値が現在の値よりも大きい場合、フィールドの値を更新します。
    • 構文: { $max: { <field>: <value>, ... } }
  • $mul: フィールドの値を指定された数値で乗算して更新します。
    • 構文: { $mul: { <field>: <value>, ... } }
  • $rename: フィールド名を新しい識別子にリネームします。
    • 構文: { $rename: { <field>: <new_name>, ... } }
  • $set: フィールドの値を指定された値に置き換えます。
    • 構文: { $set: { <field>: value, ... } }
  • $setOnInsert: upsert 操作中に、新しいドキュメントが作成される場合にのみフィールドの値を設定し、それ以外の場合は何もしません。
    • 構文: { $setOnInsert: { <field>: <value>, ... } }
  • $unset: ドキュメントからフィールドを削除します。
    • 構文: { $unset: { <field>: "", ... } }
  • $: クエリを満たす最初の配列要素のプレースホルダー。
    • 構文: { <update_operator>: {<array>.$: <value> } }
  • $[]: クエリを満たすすべての配列要素のプレースホルダー。
    • 構文: { <update_operator>: { <array>.$[]: <value> } }
  • $addToSet: 配列にまだ存在しない値を追加します。
    • 構文: { $addToSet: { <field>: <value>, ... } }
  • $pop: 配列の最初または最後の要素を削除します。
    • 構文: { $pop: { <field>: (-1 or 1), ... } }
  • $pull: 条件に一致する配列のすべての要素を削除します。
    • 構文: { $pull: { <field>: <condition>, ... } }
  • $push: 配列に値を追加します。
    • 構文: { $push: { <field>: <value>, ... } }
  • $pullAll: 指定されたすべての要素を配列から削除します。
    • 構文: { $pullAll: { <field>: [ <value>, ... ], ...} }
  • $each: $addToSet および $push オペレーターを変更して、配列全体を単一の要素としてではなく、配列の各要素を追加するようにします。
    • 構文: { <update_operator>: { <field>: { $each: [ <value>, ... ] }, ... } }
  • $position: $each とともに使用され、$push オペレーターが挿入する位置を指定します。
    • 構文: { $push: { <field>: { $each: [ <value>, ... ], $position: <num> } } }
  • $slice: $each および $push とともに使用され、配列内の要素の総数を制限します。
    • 構文: { $push: { <field>: { $each: [ <value>, ... ], $slice: <num> } } }
  • $sort: $each および $push とともに使用され、配列要素をソートします。
    • 構文: { $push: { <field>: { $each: [ <value>, ... ], $sort: <sort_order> } } }

これらのさまざまな更新オペレーターを使用すると、ドキュメントのさまざまなフィールドを異なる方法で更新できます。

コレクション内の単一ドキュメントの更新

MongoDB の updateOne() メソッドは、コレクション内の単一のドキュメントを更新するために使用されます。このメソッドは、2 つの必須引数と、オプションの引数を指定するドキュメントを受け取ります。

最初の引数は、ドキュメントを選択するために使用されるフィルター条件を指定するドキュメントです。updateOne() メソッドはコレクション内の最大 1 つのドキュメントを変更するため、フィルター条件を満たす最初のドキュメントが使用されます。

2 番目の引数は、実行される更新操作を指定します。上記の更新操作をここで指定して、一致したドキュメントの内容を変更できます。

3 番目の引数は、メソッドの動作を変更するためのさまざまなオプションのドキュメントです。最も重要な可能性のある値は次のとおりです。

  • upsert: フィルターがいずれの既存ドキュメントとも一致しない場合に新しいドキュメントを挿入することで、操作を upsert プロシージャに変換します。
  • collation: 操作に適用される言語固有のルールを定義するドキュメント。

例として、_id フィールドでフィルタリングして、正しいドキュメントをターゲットにしていることを確認し、単一の生徒レコードを更新できます。grade_level を新しい値に設定できます。

db.students.updateOne(
{ _id: ObjectId("60e8792d4655cbf49ff7cb89") },
{ $set: { grade_level: 3 } }
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

コレクション内の複数ドキュメントの更新

MongoDB の updateMany() メソッドは updateOne() メソッドと同様に機能しますが、最初のマッチで停止するのではなく、指定されたフィルターに一致するすべてのドキュメントを更新します。

updateMany() の構文は updateOne() の構文とまったく同じなので、唯一の違いは操作の範囲です。

例として、teachers コレクションのドキュメント内の subjects 配列にある「composition」のすべてのインスタンスを「writing」に変更したい場合は、次のようなものを使用できます。

db.teachers.updateMany(
{ subject: "composition" },
{ $set: { "subjects.$": "writing" } }
)
{ "acknowledged" : true, "matchedCount" : 3, "modifiedCount" : 3 }

ドキュメントを確認すると、「composition」のすべてのインスタンスが「writing」に置き換えられているはずです。

db.teachers.find()
{ "_id" : ObjectId("60eddca65eb74f5c676f3baa"), "first_name" : "Nancy", "last_name" : "Smith", "subjects" : [ "vocabulary", "pronunciation" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bab"), "first_name" : "Ronald", "last_name" : "Taft", "subjects" : [ "literature", "grammar", "writing" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bac"), "first_name" : "Casey", "last_name" : "Meyers", "subjects" : [ "literature", "writing", "grammar" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bad"), "first_name" : "Rebecca", "last_name" : "Carrie", "subjects" : [ "grammar", "literature" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bae"), "first_name" : "Sophie", "last_name" : "Daggs", "subjects" : [ "literature", "writing", "grammar", "vocabulary", "pronunciation" ] }

ドキュメントの置き換え

replaceOne() メソッドは updateOne() メソッドと似ていますが、個々のフィールドを更新するのではなく、ドキュメント全体を置き換えます。構文は前の 2 つのコマンドと同じです。

たとえば、Nancy Smith があなたの学校を去り、文学を教える Clara Newman という教師に置き換える場合、次のように入力できます。

db.teachers.replaceOne(
{
$and: [
{ first_name: "Nancy" },
{ last_name: "Smith" }
]
},
{
first_name: "Clara",
last_name: "Newman",
subjects: [ "literature" ]
}
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

一致したドキュメントが削除され、指定したドキュメントが置き換えられたことがわかります。

db.teachers.find()
{ "_id" : ObjectId("60eddca65eb74f5c676f3baa"), "first_name" : "Clara", "last_name" : "Newman", "subjects" : [ "literature" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bab"), "first_name" : "Ronald", "last_name" : "Taft", "subjects" : [ "literature", "grammar", "writing" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bac"), "first_name" : "Casey", "last_name" : "Meyers", "subjects" : [ "literature", "writing", "grammar" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bad"), "first_name" : "Rebecca", "last_name" : "Carrie", "subjects" : [ "grammar", "literature" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bae"), "first_name" : "Sophie", "last_name" : "Daggs", "subjects" : [ "literature", "writing", "grammar", "vocabulary", "pronunciation" ] }

ドキュメントを削除する方法

コレクションからのドキュメントの削除も、ドキュメントのライフサイクルの一部です。deleteOne() または deleteMany() メソッドを使用してドキュメントを削除できます。これらは同じ構文を持ち、操作するドキュメントの数のみが異なります。

ほとんどの場合、これらのメソッドのいずれかを使用してドキュメントを削除するには、削除するドキュメントを選択する方法を指定するフィルタードキュメントを提供するだけです。deleteOne() メソッドは、最大 1 つのドキュメントを削除します (フィルターが生成するマッチの数に関係なく) が、deleteMany() メソッドはフィルター条件に一致するすべてのドキュメントを削除します。

たとえば、単一の学生を削除するには、_id を指定して明示的にマッチさせることができます。

db.students.deleteOne({
_id: ObjectId("60e8792d4655cbf49ff7cb87")
})
{ "acknowledged" : true, "deletedCount" : 1 }

学年レベルが割り当てられていない生徒をすべて削除したい場合は、代わりに deleteMany() メソッドを使用できます。

db.students.deleteMany({
grade_level: { $eq: null }
})
{ "acknowledged" : true, "deletedCount" : 2 }

確認すると、残りのすべての生徒に学年レベルが割り当てられているはずです。

db.students.find()
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler", "grade_level" : 3 }

まとめ

ドキュメントの作成、クエリ、更新、削除の方法を学ぶことで、MongoDB でドキュメントを日々効果的に管理するために必要なスキルが身につきます。さまざまなドキュメントとコレクションのメソッド、および情報のマッチングと変更を可能にするオペレーターに習熟することで、データベースシステムが理解できる複雑な思考を表現できるようになります。

FAQ

MongoDB の 埋め込みドキュメント、またはネストされたドキュメント とは、その内部に別のドキュメントを含むドキュメントのことです。

以下は埋め込みドキュメントの例で、address(追加の中括弧でサブドキュメントとして示されている)は user レコードでアクセスできます。

db.user.findOne({_id: 111111})
{
_id: 111111,
email: “email@example.com”,
name: {given: “Jane”, family: “Han”},
address: {
street: “111 Elm Street”,
city: “Springfield”,
state: “Ohio”,
country: “US”,
zip: “00000”,
}
}

MongoDB の最大ドキュメントサイズは 16 メガバイトです。

この制限は、単一のドキュメントが過剰な RAM や、転送時に過剰な帯域幅を使用しないようにするのに役立ちます。

16MB を超えるドキュメントを保存するために、MongoDB は GridFS API を提供しています。

ドキュメントを削除するには、deleteOne() または deleteMany() メソッドを使用できます。これらは同じ構文を持ち、操作するドキュメントの数のみが異なります。

単一のドキュメントを削除する場合、特定の _id を持つドキュメントを削除する基本的な構文は次のようになります。

db.students.deleteOne({
_id: ObjectId("60e8792d4655cbf49ff7cb87")
})

そして、特定の条件に一致する複数のドキュメントを削除する構文も同様です。

db.students.deleteMany({
grade_level: { $eq: null }
})

MongoDB でドキュメントを変更するには、いくつかの 関連する更新メソッド があります。

具体的に、ドキュメントに新しいデータを追加するには、$addToSet 更新オペレーター を使用できます。このオペレーターは、まだ存在しない場合にのみドキュメントの配列に値を追加します。

MongoDB には、あるドキュメントと別のドキュメントを明示的に比較する特定のメソッドはありません。オペレーター を使用して、ドキュメントの任意のフィールド間の等価性を比較するクエリを構成することで可能です。

比較は、集計パイプライン を構成することによっても行うことができます。このメソッドを使用すると、次のステージを作成できます。

  • 複数のドキュメントから値をグループ化する
  • グループ化されたデータに対して操作を実行し、単一の結果を返す
  • 時間の経過に伴うデータ変更を分析する
著者について
Justin Ellingwood

ジャスティン・エリングウッド

ジャスティンは 2013 年からデータベース、Linux、インフラ、開発者ツールについて執筆しています。現在は妻と 2 匹のウサギと共にベルリンに住んでいます。彼は通常、三人称で書く必要がないので、関係者全員にとって安心です。
© . All rights reserved.