はじめに
この実験 (Lab) では、MongoDB で埋め込みドキュメント (embedded documents) を効果的に管理する方法を学びます。埋め込みドキュメント、またはネストされたドキュメントは、MongoDB のデータモデルの中核的な機能であり、単一のドキュメント内に複雑で階層的なデータを格納することを可能にします。ネストされたデータを持つドキュメントの作成、それらのドキュメント内の特定のフィールドの更新、要素の削除、そしてこれらの複雑な構造のクエリなど、幅広いテクニックを習得します。また、スキーマ検証 (schema validation) を使用して一貫したデータ構造を強制する方法も学びます。これらのスキルは、MongoDB を使用して堅牢で効率的なアプリケーションを構築するために不可欠です。
ネストされたデータを持つドキュメントの作成
このステップでは、MongoDB でネストされた構造を持つドキュメントを作成する方法を学びます。これは、関連するデータを単一のドキュメント内にモデリングするための基本的なスキルです。
まず、MongoDB シェル (mongosh) を開いてデータベースとの対話を開始します。この実験 (Lab) での以降のすべてのコマンドは、特に指定がない限り、このシェル内で実行されます。
mongosh
次に、bookstore という名前の新しいデータベースに切り替えます。このデータベースが存在しない場合、MongoDB は最初にデータを格納したときに自動的に作成します。
use bookstore
次に、books という名前のコレクションを作成し、単一のドキュメントを挿入します。このドキュメントには、本の詳細を表すネストされたオブジェクトとネストされたオブジェクトの配列が含まれます。
db.books.insertOne({
title: "Advanced MongoDB",
author: {
name: "Jane Smith",
contact: {
email: "jane.smith@example.com",
phone: "+1-555-123-4567"
}
},
published: {
year: 2023,
publisher: "Tech Publications"
},
chapters: [
{ number: 1, title: "Introduction to Nested Documents" },
{ number: 2, title: "Advanced Document Structures" }
]
})
作成したドキュメントでは:
authorとpublishedはネストされたドキュメント(オブジェクト)です。authorドキュメントには、別のネストされたドキュメントであるcontactが含まれています。chaptersは配列であり、それぞれが章を表す複数のネストされたドキュメントが含まれています。
ドキュメントを表示してその構造を確認するには、find() メソッドを使用します。
db.books.find()
以下のような出力が表示され、ドキュメントが正しく挿入されたことを確認できます。_id は MongoDB によって自動的に生成される一意の識別子です。
[
{
_id: ObjectId("..."),
title: 'Advanced MongoDB',
author: {
name: 'Jane Smith',
contact: {
email: 'jane.smith@example.com',
phone: '+1-555-123-4567'
}
},
published: {
year: 2023,
publisher: 'Tech Publications'
},
chapters: [
{ number: 1, title: 'Introduction to Nested Documents' },
{ number: 2, title: 'Advanced Document Structures' }
]
}
]
ネストされたフィールドと配列要素の更新
ドキュメントを作成した後、それらの一部を変更する必要があることがよくあります。このステップでは、ネストされたドキュメントや配列内の特定のフィールドを更新する方法を学びます。前のステップから引き続き mongosh シェルを使用してください。
まず、著者の連絡先情報を更新しましょう。これを行うには、変更したいフィールドへの正確なパスを指定するために、ドット表記 (dot notation) を使用した $set 演算子を使用します。このコマンドは、電話番号を変更し、新しい website フィールドを追加します。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $set: {
"author.contact.phone": "+1-888-999-0000",
"author.contact.website": "www.janesmith.com"
} }
)
ドット表記 "author.contact.phone" は、MongoDB に対して author オブジェクトに入り、次に contact オブジェクトに入り、phone フィールドを更新するように指示します。
次に、$push 演算子を使用して chapters 配列に新しい章を追加します。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $push: {
chapters: {
number: 3,
title: "MongoDB Advanced Techniques"
}
} }
)
配列内の特定の要素を更新することもできます。最初の章のタイトルを変更してみましょう。ここでは、クエリ条件 ("chapters.number": 1) に一致する最初の配列要素のプレースホルダーとして機能する、位置指定子 $ を使用します。
db.books.updateOne(
{ title: "Advanced MongoDB", "chapters.number": 1 },
{ $set: {
"chapters.$.title": "Introduction to Nested Documents (Revised)"
} }
)
すべての変更を確認するために、ドキュメントを再度取得します。.pretty() メソッドは、出力をより読みやすくフォーマットします。
db.books.find({ title: "Advanced MongoDB" }).pretty()
出力には、更新された電話番号、新しいウェブサイト、追加された 3 番目の章、および最初の章の改訂されたタイトルが表示されます。
ネストされたフィールドと配列要素の削除
このステップでは、ドキュメントの一部を削除する方法を学びます。これには、特定のフィールド、ネストされたドキュメント全体、および配列からの要素の削除が含まれます。
まず、$unset 演算子を使用して、著者の連絡先情報から website フィールドを削除しましょう。$unset に提供される値(この場合は空文字列 "")は重要ではありません。演算子は指定されたフィールドを削除するだけです。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $unset: { "author.contact.website": "" } }
)
次に、配列から要素を削除します。$pull 演算子を使用して、chapters 配列から 3 番目の章(number: 3 を持つもの)を削除しましょう。$pull 演算子は、指定された条件に一致するすべての配列要素を削除します。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $pull: {
chapters: { number: 3 }
} }
)
最後に、ネストされたオブジェクト全体を削除できます。ここでも $unset 演算子を使用して、author ドキュメントから contact オブジェクトを削除しましょう。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $unset: { "author.contact": "" } }
)
これらの削除操作の結果を確認するために、ドキュメントを再度クエリします。
db.books.find({ title: "Advanced MongoDB" }).pretty()
出力には、website フィールドと contact オブジェクト全体が削除され、chapters 配列には 2 つの要素のみが含まれていることが示されます。
ネストされたデータを持つドキュメントのクエリ
クエリは基本的なデータベース操作です。このステップでは、ネストされたオブジェクトや配列内の値に基づいてドキュメントをクエリする方法を学びます。これらの例のためにクリーンなデータセットを確保するために、まず既存の books コレクションを削除します。
db.books.drop()
次に、クエリの練習のために、異なるネスト構造を持つ新しいドキュメントをいくつか挿入します。
db.books.insertMany([
{
title: "MongoDB Essentials",
author: {
name: "John Doe",
experience: { years: 5, specialization: "Database Design" }
},
tags: ["beginner", "database", "nosql"],
chapters: [
{ number: 1, title: "Introduction", pages: 25 },
{ number: 2, title: "Advanced Concepts", pages: 45 }
]
},
{
title: "Advanced Database Techniques",
author: {
name: "Jane Smith",
experience: { years: 8, specialization: "Distributed Systems" }
},
tags: ["advanced", "distributed", "nosql"],
chapters: [
{ number: 1, title: "System Design", pages: 35 },
{ number: 2, title: "Performance Optimization", pages: 55 }
]
}
])
ネストされたドキュメントのフィールドで書籍を検索するには、ドット表記を使用します。このクエリは "John Doe" によって書かれた書籍を見つけます。
db.books.find({ "author.name": "John Doe" })
ネストされた構造のさらに奥深くに進むことができます。このクエリは、著者の専門分野が "Database Design" である書籍を見つけます。
db.books.find({ "author.experience.specialization": "Database Design" })
配列に特定の値が含まれているドキュメントを見つけるには、配列フィールドを直接クエリできます。これは "nosql" タグが付いたすべての書籍を見つけます。
db.books.find({ tags: "nosql" })
配列要素が特定の条件を満たしているドキュメントをクエリすることもできます。このクエリは、$gt(より大きい)演算子を使用して、40 ページを超える章を少なくとも 1 つ持つ書籍を見つけます。
db.books.find({ "chapters.pages": { $gt: 40 } })
最後に、複数の条件を組み合わせることができます。このクエリは、"advanced" タグが付いており、5 年以上の経験を持つ著者によって書かれた書籍を見つけます($gte は以上を意味します)。
db.books.find({
"author.experience.years": { $gte: 5 },
tags: "advanced"
})
スキーマ検証によるドキュメント構造の強制
データの一貫性を維持するために、MongoDB では JSON Schema 検証を使用してコレクション内のドキュメントに特定の構造を強制することができます。このステップでは、すべてのドキュメントが定義済みの構造に従うことを保証するバリデーターを持つ新しいコレクションを作成します。
まず、courses という名前の新しいコレクションを作成します。作成時に、スキーマ規則を含む validator オプションを渡します。
db.createCollection("courses", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["title", "instructor", "duration", "topics"],
properties: {
title: {
bsonType: "string",
description: "must be a string and is required"
},
instructor: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: { bsonType: "string" },
email: {
bsonType: "string",
pattern: "^.+@.+$"
}
}
},
duration: {
bsonType: "int",
minimum: 1,
maximum: 100
},
topics: {
bsonType: "array",
minItems: 1,
items: { bsonType: "string" }
}
}
}
}
})
このスキーマは、各ドキュメントに title、instructor、duration、および topics が含まれていることを要求します。また、各フィールドのデータ型も定義しており、instructor オブジェクトと topics 配列にはネストされた規則が含まれています。
次に、これらの規則に準拠したドキュメントを挿入してみます。この操作は成功するはずです。
db.courses.insertOne({
title: "MongoDB Advanced Techniques",
instructor: {
name: "Jane Smith",
email: "jane.smith@example.com"
},
duration: 40,
topics: ["Nested Documents", "Schema Validation"]
})
次に、スキーマ規則に違反するドキュメントを挿入してみます。このドキュメントは、instructor.name のデータ型が間違っており、無効なメール形式、許可された範囲外の duration、および空の topics 配列を持っています。
db.courses.insertOne({
title: "Invalid Course",
instructor: {
name: 123,
email: "invalid-email"
},
duration: 200,
topics: []
})
この挿入は失敗し、MongoDB は Document failed validation エラーを返します。これにより、一貫性のないデータが保存されるのを防ぎ、データベースの整合性を維持するのに役立ちます。
まとめ
この実験では、MongoDB で埋め込みドキュメントを管理するための基本的なテクニックを学びました。複雑なネスト構造(オブジェクトや配列を含む)を持つドキュメントの作成から始めました。次に、ドット表記や $set、$push のような演算子を使用して特定のフィールドを更新する練習をしました。また、$unset や $pull を使ってデータを削除する方法も学びました。さらに、ネストされたデータに対するターゲットを絞ったクエリの実行方法、そして最後に、JSON Schema バリデーターをコレクションに定義して適用することでデータ整合性を強制する方法を探求しました。これらのスキルは、MongoDB の柔軟なドキュメントモデルを効果的に活用するアプリケーションを構築する上で非常に重要です。

