1. MongoDB の概要
MongoDBとは何ですか?
MongoDB は、2009 年に初めてリリースされた、オープンソースのドキュメント指向の非リレーショナル データベース管理システムです。従来の行と列の表形式ではなく、BSON を使用して JSON のようなドキュメントにデータを保存します。
MongoDB は、大量のデータを処理するときに高いパフォーマンスとスケーラビリティを提供するように設計されています。最新のアプリケーションの柔軟性、拡張性、データの複雑さの要件を満たすように設計されています。
MongoDB の機能と利点
-
ドキュメント指向のデータ モデル: MongoDB は、BSON (バイナリ JSON) と呼ばれるバイナリ表現を使用してデータを保存します。ドキュメントは JSON に似た構造で、キーと値のペア、配列、ネストされたドキュメントを含めることができます。この柔軟なデータ モデルにより、MongoDB はさまざまなタイプや構造のデータを簡単に保存および処理できます。
-
高いパフォーマンスとスケーラビリティ: MongoDB は、メモリ マップド ストレージ エンジンを使用して、交換のために物理メモリとディスクの間にデータを保存し、高速な読み取りおよび書き込み操作を実現します。さらに、MongoDB は水平拡張もサポートしており、クラスター内にサーバー ノードを追加することで、処理能力とストレージ容量を向上させ、大規模なデータや高い同時アクセスのニーズを満たすことができます。
-
強力なクエリ機能: MongoDB は、豊富なクエリ言語と柔軟なクエリ方法を提供します。範囲クエリ、並べ替え、集計、グループ化など、さまざまな種類のクエリ操作をサポートします。同時に、MongoDB は、さまざまなアプリケーション シナリオでのデータ取得のニーズを満たすために、全文検索、地理空間クエリ、グラフ クエリなどの特殊なタイプのクエリもサポートしています。
-
データ レプリケーションと障害回復: MongoDB は、データの信頼性と高可用性を確保するために、データ レプリケーションと障害回復メカニズムをサポートしています。レプリカセット(レプリカセット)を構成することで、複数のノードにデータを複製したり、フェイルオーバーやフェイルオーバーを自動的に実行して、障害発生時にもシステムがサービスを提供し続けることができます。
-
スケーラビリティと柔軟なスケーラビリティ: MongoDB はシャーディングを通じて水平拡張を実現します。フラグメンテーションとは、データを一定のルールに従って複数のフラグメントに分割し、各フラグメントを別のサーバーに保存することで、負荷分散とシームレスなデータ拡張を実現します。
-
セキュリティとアクセス制御: MongoDB は、データの機密性と整合性を保護するセキュリティ メカニズムを提供します。認証、アクセス制御、データ暗号化などの機能をサポートしており、データベースへのユーザー アクセスを制限し、機密データのセキュリティを保護できます。
2. MongoDB の基本概念と用語
文書データベースの基本概念
ドキュメント データベースは、データをドキュメントの形式で編成して保存する非リレーショナル データベース (NoSQL) です。
-
ドキュメント: ドキュメントはドキュメント データベースの最も基本的な単位であり、JSON 形式または JSON に類似した構造化テキストの場合があります。ドキュメントは固定スキーマに従う必要はなく、半構造化データであってもかまいません。ドキュメントは通常、キーと値のペアとして表されます。キーはフィールド名で、値は文字列、数値、ブール値、配列、ネストされたオブジェクトなどのさまざまなデータ型になります。
-
コレクション: コレクションは、複数の関連ドキュメントをまとめて整理できるドキュメントのコンテナーです。コレクションはリレーショナル データベースのテーブルの概念に似ていますが、ドキュメント データベースでは、コレクション内のドキュメントは異なる構造を持つことができるため、柔軟性が高くなります。
-
スキーマフリー: ドキュメントデータベースはスキーマフリーです。つまり、ドキュメントごとに異なるフィールドや構造を持つことができます。これにより、ドキュメント データベースは、事前に定義されたテーブル構造やスキーマが必要なく、必要に応じてフィールドを柔軟に追加または変更できるため、半構造化データや変化するデータの保存に非常に適しています。
-
ネストされたドキュメント: ドキュメント データベースは、ネストされたドキュメント、つまり、あるドキュメント内に別のドキュメントをネストすることをサポートします。これは、データを階層的に編成できるため、複雑なデータ構造をデータベースに直接マッピングできることを意味します。
-
クエリ言語: ドキュメント ベースのデータベースは、豊富なクエリ言語と柔軟なクエリ方法を提供し、範囲クエリ、並べ替え、集計、グループ化など、ドキュメントに対してさまざまな種類のクエリ操作を実行できます。クエリ言語は通常 SQL に似た構文を使用しますが、ドキュメント データベース専用に設計された他のクエリ言語も使用できます。
-
スケーラビリティ: ドキュメント データベースは優れたスケーラビリティを備えており、サーバー ノードを追加することでストレージ容量と処理能力を向上させることができます。一部のドキュメント データベースは、データを水平に分割して異なるマシンに保存するシャーディング テクノロジーもサポートしており、より高いスループットと負荷分散を実現します。
-
高いパフォーマンス: ドキュメント データベースはデータをドキュメント形式で保存し、通常はメモリ マッピング テクノロジを使用してデータをメモリに保存するため、高速な読み取りおよび書き込みパフォーマンスを備えています。同時に、ドキュメント データベースはインデックス作成とクエリ最適化テクノロジもサポートしており、クエリを高速化できます。
一般に、ドキュメント データベースは、柔軟なデータ モデル、自由なスキーマ、ネストされたドキュメント、強力なクエリ機能、優れたスケーラビリティを備え、データをドキュメント単位で保存します。半構造化データや可変データの保存に適しており、高いパフォーマンスと柔軟性を提供し、さまざまな種類のアプリケーションで広く使用されています。
コレクションとドキュメント
ドキュメント データベースでは、コレクションとドキュメントはデータの整理と保存に使用される 2 つの基本概念です。
- コレクション:
コレクションは、ドキュメント データベースの論理概念であり、リレーショナル データベースのテーブルと同様です。これは関連ドキュメントのセットのコンテナであり、複数のドキュメントを含めることができます。各コレクションには、データベース内でコレクションを識別する一意の名前が付いています。
-
コレクションには固定構造がありません。リレーショナル データベースのテーブルとは異なり、コレクションには固定スキーマやフィールドのリストを事前に定義する必要がありません。コレクション内のドキュメントはさまざまな構造を持つことができ、必要に応じてフィールドを柔軟に追加、変更、削除できます。これにより、コレクションは半構造化データや変化するデータの保存に最適になります。
-
コレクションには独立したアクセス許可制御があります。コレクションは独立したアクセス許可とアクセス制御を定義でき、コレクション内のデータの読み取りおよび書き込みアクセス許可を正確に制御できます。これにより、マルチユーザーまたはマルチアプリケーション環境でのデータの管理と保護が容易になります。
- ドキュメント:
ドキュメントはドキュメント データベースに保存される基本単位であり、リレーショナル データベースの行と同様に、キーと値のペアのコレクションとみなすことができます。各ドキュメントは構造化データ オブジェクトであり、通常は JSON のような形式を使用して表現されます。
-
ドキュメントはキーと値のペアを使用して表現されます。ドキュメントは一連のキーと値のペアで構成されます。キーはフィールド名で、値は文字列、数値、ブール値、配列、ネストされたものなどのさまざまなデータ型になります。オブジェクトなど これにより、ドキュメントが非常に柔軟になり、複雑なデータ構造を保存できるようになります。
-
ドキュメントには固定のスキーマがありません。リレーショナル データベースの行とは異なり、ドキュメントはさまざまなフィールドや構造を持つことができます。各ドキュメントは必要に応じて独自のフィールドを定義でき、フィールドはいつでも追加、削除、変更できます。この柔軟性により、開発者は変化するニーズに合わせてデータ モデルを動的に調整できます。
-
ドキュメントはネスト可能: ドキュメントはネストされた構造をサポートしています。つまり、1 つのドキュメントが別のドキュメント内にネストされています。これは、データを階層的に編成して表現できるため、複雑なデータ構造をデータベースに直接マッピングできることを意味します。
コレクションとドキュメントはドキュメント データベースにおける重要な概念であり、柔軟で動的かつ階層的なデータ ストレージを提供します。コレクションは、複数の関連ドキュメントを整理するために使用され、ドキュメントは実際のデータ コンテンツを保存および表現するための最も基本的な単位です。コレクションとドキュメントを組み合わせて使用することにより、ドキュメント データベースは半構造化された変更可能なデータ ストレージ要件を満たし、高い柔軟性と拡張性を提供できます。
BSONデータ形式
BSON (バイナリ JSON) は、ドキュメント データベースにデータを保存および交換するためのバイナリ シリアル化データ形式です。これは、JSON に似た軽量で効率的なデータ表現形式ですが、データはバイナリ形式で保存され、次の特徴があります。
-
バイナリ形式: BSON はバイナリ エンコーディングを使用してデータを表現します。プレーン テキストの JSON 形式と比較して、BSON はデータの保存と送信に必要なスペースが少なく、データの解析と処理の効率が高くなります。
-
サポートされているデータ型: BSON は、文字列、整数、浮動小数点数、ブール値、日付と時刻、正規表現、配列、ネストされたドキュメントなどの一般的なデータ型をサポートしています。さらに、BSON はバイナリ データ、オブジェクト ID、タイムスタンプ、長整数などの特殊な型もサポートします。
-
埋め込みドキュメントと配列: JSON と同様に、BSON ではドキュメント内で他のドキュメントや配列をネストできるため、複雑なデータ構造を表現できます。ネストされたドキュメントと配列は、ネストされた BSON オブジェクトとして再帰的にエンコードされます。
-
フィールドの順序: BSON データはフィールドの順序でエンコードされるため、BSON のフィールドの順序は意味があります。これは、データの保存および転送時にフィールドの順序が変更されず、データの一貫性が確保されることを意味します。
-
インデックス作成とクエリ: 通常、BSON データはバイナリ形式でディスクに保存されるため、ドキュメント データベースはインデックス作成とクエリ最適化技術を使用して、データ アクセスとクエリ操作を高速化できます。たとえば、特定のフィールドに対してインデックスを作成すると、クエリ時に一致するドキュメントをすばやく見つけることができます。
-
言語サポート: BSON は広くサポートされており、一般的なデータ シリアル化形式として使用されています。多くのプログラミング言語とデータベース システムは、開発者がさまざまな環境でのデータ処理に BSON を使用できるようにするために、BSON と対話するライブラリとドライバーを提供しています。
一般に、BSON は、ドキュメント データベースにデータを保存および交換するためのバイナリ データ形式です。効率的でコンパクトなストレージ形式を持ち、複数のデータ型とネストされた構造をサポートし、インデックス作成とクエリの最適化を通じて高速なデータ アクセスを実現します。BSON は、ドキュメント データベースの基盤の 1 つとして、大量のデータと複雑なデータ構造を伴うシナリオで重要な役割を果たします。
3. MongoDBのCRUD操作
文書を作成する
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
public class DocumentCreationExample {
public static void main(String[] args) {
// 连接到MongoDB数据库
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 选择数据库
MongoDatabase database = mongoClient.getDatabase("mydatabase");
// 选择集合
MongoCollection<Document> collection = database.getCollection("mycollection");
// 创建文档
Document document = new Document();
document.append("name", "John Doe");
document.append("age", 30);
document.append("email", "[email protected]");
// 将文档插入集合
collection.insertOne(document);
// 打印插入的文档ID
System.out.println("Inserted document ID: " + document.get("_id"));
// 关闭数据库连接
mongoClient.close();
}
}
文書を読む
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
public class DocumentReadExample {
public static void main(String[] args) {
// 连接到MongoDB数据库
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 选择数据库
MongoDatabase database = mongoClient.getDatabase("mydatabase");
// 选择集合
MongoCollection<Document> collection = database.getCollection("mycollection");
// 创建查询条件
Document query = new Document();
query.append("name", "John Doe");
// 执行查询操作
MongoCursor<Document> cursor = collection.find(query).iterator();
while (cursor.hasNext()) {
Document document = cursor.next();
// 读取文档的字段值
String name = document.getString("name");
int age = document.getInteger("age");
String email = document.getString("email");
// 打印文档字段值
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Email: " + email);
}
// 关闭游标
cursor.close();
// 关闭数据库连接
mongoClient.close();
}
}
Document
上記の例では、クエリ条件のオブジェクトを作成します。ここではname
、クエリのフィールドは「John Doe」です。次に、find
メソッドを使用してクエリ操作を実行し、MongoCursor
取得したドキュメントを反復処理します。
getString
各ドキュメントについて、や などのメソッドを使用して対応するフィールドの値を読み取り、getInteger
出力します。最後に、カーソルとデータベース接続が閉じられます。
ドキュメントを更新する
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
public class DocumentUpdateExample {
public static void main(String[] args) {
// 连接到MongoDB数据库
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 选择数据库
MongoDatabase database = mongoClient.getDatabase("mydatabase");
// 选择集合
MongoCollection<Document> collection = database.getCollection("mycollection");
// 定义更新条件
Document query = new Document();
query.append("name", "John Doe");
// 定义更新操作
Document update = new Document();
update.append("$set", new Document("age", 35));
// 执行更新操作
collection.updateOne(query, update);
// 关闭数据库连接
mongoClient.close();
}
}
上の例では、Document
条件のオブジェクトを更新します。ここでは、name
フィールドが「John Doe」と一致するように更新します。次に、フィールドを 35 に更新する演算子Document
を使用して、更新操作のオブジェクトを定義します。最後に、メソッドを使用して更新操作を実行します。$set
age
updateOne
文書を削除する
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
public class DocumentDeleteExample {
public static void main(String[] args) {
// 连接到MongoDB数据库
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 选择数据库
MongoDatabase database = mongoClient.getDatabase("mydatabase");
// 选择集合
MongoCollection<Document> collection = database.getCollection("mycollection");
// 定义删除条件
Document query = new Document();
query.append("name", "John Doe");
// 执行删除操作
collection.deleteOne(query);
// 关闭数据库连接
mongoClient.close();
}
}
上記の例では、deleteOne
メソッドを使用して削除操作を実行します。
複数のドキュメントを削除する場合は、deleteMany
メソッドを使用して、適切なクエリ条件を指定できます。この方法を使用すると、クエリ条件を満たすすべてのドキュメントが削除されます。
4、MongoDB クエリ操作
基本的なクエリ
すべてのドキュメントをクエリする
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
public class GetAllDocumentsExample {
public static void main(String[] args) {
// 连接到MongoDB数据库
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 选择数据库
MongoDatabase database = mongoClient.getDatabase("mydatabase");
// 选择集合
MongoCollection<Document> collection = database.getCollection("mycollection");
// 执行查询操作
MongoCursor<Document> cursor = collection.find().iterator();
// 遍历结果
while (cursor.hasNext()) {
Document document = cursor.next();
System.out.println(document.toJson());
}
// 关闭游标
cursor.close();
// 关闭数据库连接
mongoClient.close();
}
}
条件付きクエリ
- 等しい: フィールド値が指定された値と等しいドキュメントをフィルターで除外します。
// 等于条件查询示例
Document query = new Document("name", "Alice");
MongoCursor<Document> cursor = collection.find(query).iterator();
- 等しくない: フィールド値が指定された値と等しくないドキュメントをフィルターで除外します。
// 不等于条件查询示例
Document query = new Document("age", new Document("$ne", 30));
MongoCursor<Document> cursor = collection.find(query).iterator();
- より大きい: 指定された値より大きいフィールド値を持つドキュメントをフィルターで除外します。
// 大于条件查询示例
Document query = new Document("age", new Document("$gt", 18));
MongoCursor<Document> cursor = collection.find(query).iterator();
- 以下: 指定された値より小さいフィールド値を持つドキュメントをフィルターで除外します。
// 小于条件查询示例
Document query = new Document("age", new Document("$lt", 40));
MongoCursor<Document> cursor = collection.find(query).iterator();
- 以上: フィールド値が指定された値以上であるドキュメントをフィルターで除外します。
// 大于等于条件查询示例
Document query = new Document("age", new Document("$gte", 20));
MongoCursor<Document> cursor = collection.find(query).iterator();
- 以下: フィールド値が指定された値以下のドキュメントをフィルターで除外します。
// 小于等于条件查询示例
Document query = new Document("age", new Document("$lte", 50));
MongoCursor<Document> cursor = collection.find(query).iterator();
- 含む (入力): 指定された値のリストにフィールド値が含まれるドキュメントをフィルターで除外します。
// 包含条件查询示例
List<String> names = Arrays.asList("Alice", "Bob");
Document query = new Document("name", new Document("$in", names));
MongoCursor<Document> cursor = collection.find(query).iterator();
- Not In: フィールド値が指定された値のリストにないドキュメントをフィルターで除外します。
// 不包含条件查询示例
List<String> names = Arrays.asList("Charlie", "Dave");
Document query = new Document("name", new Document("$nin", names));
MongoCursor<Document> cursor = collection.find(query).iterator();
- 正規表現: 正規表現を使用して、パターンに一致するドキュメントを除外します。
// 正则表达式条件查询示例
Pattern pattern = Pattern.compile("^A.*e$");
Document query = new Document("name", pattern);
MongoCursor<Document> cursor = collection.find(query).iterator();
射影クエリ
プロジェクション クエリとは、クエリ プロセス中にドキュメント全体を返すのではなく、必要なフィールドのみを返すことを指します。この方法により、クエリ効率が向上し、ネットワーク上で送信されるデータ量が削減されます。
- Include: 指定されたフィールドのみを返し、他のフィールドは返されません。
// 包含投影查询示例
Document query = new Document();
Document projection = new Document("name", 1).append("age", 1);
MongoCursor<Document> cursor = collection.find(query).projection(projection).iterator();
上記の例では、ドキュメント内の「名前」フィールドと「年齢」フィールドのみが返され、他のフィールドは結果から除外されます。
- Exclude: 指定されたフィールドを除くすべてのフィールドを返します。
// 排除投影查询示例
Document query = new Document();
Document projection = new Document("name", 0).append("address", 0);
MongoCursor<Document> cursor = collection.find(query).projection(projection).iterator();
上の例では、「名前」フィールドと「住所」フィールドを除くすべてのフィールドが返されます。
- ネストされたフィールドの投影: ドット「.」記号を投影操作で使用して、ネストされたフィールドを表すことができます。
// 嵌套字段的投影查询示例
Document query = new Document();
Document projection = new Document("name", 1).append("address.city", 1);
MongoCursor<Document> cursor = collection.find(query).projection(projection).iterator();
上の例では、「name」フィールドとネストされたフィールド「address.city」が返されますが、他のネストされたフィールドは返されません。
- 配列フィールドの射影: 射影操作でインデックス番号を使用して、配列フィールド内の特定の要素を示すことができます。
// 数组字段的投影查询示例
Document query = new Document();
Document projection = new Document("name", 1).append("hobbies.0", 1);
MongoCursor<Document> cursor = collection.find(query).projection(projection).iterator();
上記の例では、「name」フィールドと配列フィールドの最初の要素「hobbies」が返され、他の配列要素は返されません。
クエリの並べ替えとページング
- 並べ替えクエリ:
並べ替えクエリでは、結果を指定したフィールドの昇順または降順に並べることができます。
// 升序排序查询示例
Document query = new Document();
Document sort = new Document("age", 1); // 按照年龄升序排列
MongoCursor<Document> cursor = collection.find(query).sort(sort).iterator();
// 降序排序查询示例
Document query = new Document();
Document sort = new Document("name", -1); // 按照姓名降序排列
MongoCursor<Document> cursor = collection.find(query).sort(sort).iterator();
上記の例では、sort
メソッドを使用してクエリ結果を並べ替えます。1
昇順と-1
降順を示します。
- ページング クエリ:
ページング クエリは、指定されたページ数とページごとのレコード数に従ってクエリ結果からデータを取得するために使用されます。
int pageNumber = 1; // 第一页
int pageSize = 10; // 每页10条记录
Document query = new Document();
Document sort = new Document("name", 1); // 按照姓名升序排列
MongoCursor<Document> cursor = collection.find(query).sort(sort)
.skip((pageNumber-1) * pageSize)
.limit(pageSize)
.iterator();
上記の例では、skip
スキップするレコード数 (つまり、前のページのレコード数) を指定するメソッドと、limit
ページごとのレコード数を指定するメソッドを使用しています。
集計クエリ
集計クエリは、ドキュメント データベース内のデータを集計するために使用されるクエリ方法です。指定された条件に従ってデータをグループ化、フィルタリング、計算、並べ替えて、統計結果を生成したり、特定の集計ルールに従ってデータを出力したりできます。
集計クエリを実行するには、通常、集計パイプラインを使用する必要があります。これは、複数の集計操作で構成されるパイプラインであり、各操作がデータを順番に処理し、結果を次の操作に渡します。以下に、一般的な集計操作をいくつか示します。
$match
: 指定した基準に基づいてドキュメントをフィルタリングします。
// 聚合查询示例 - $match操作
List<Bson> pipeline = Arrays.asList(
Aggregates.match(Filters.eq("status", "active"))
);
AggregateIterable<Document> results = collection.aggregate(pipeline);
上の例では、$match
アクションを使用して、「ステータス」フィールドの値が「アクティブ」であるドキュメントを除外します。
$group
: 指定されたフィールドに従ってデータをグループ化し、カウントや合計などのグループ化操作を実行します。
// 聚合查询示例 - $group操作
List<Bson> pipeline = Arrays.asList(
Aggregates.group("$category", Accumulators.sum("totalQty", "$quantity"))
);
AggregateIterable<Document> results = collection.aggregate(pipeline);
上記の例では、$group
演算を使用してデータを「カテゴリ」フィールドごとにグループ化し、$sum
演算子を使用して各グループの「数量」フィールドを合計します。
$project
: 射影操作は、出力のフィールドを選択するために使用されます。
// 聚合查询示例 - $project操作
List<Bson> pipeline = Arrays.asList(
Aggregates.match(Filters.eq("status", "active")),
Aggregates.project(Projections.include("name", "price"))
);
AggregateIterable<Document> results = collection.aggregate(pipeline);
上記の例では、$project
アクションを使用して出力フィールドを選択し、「名前」フィールドと「価格」フィールドのみが含まれています。
$sort
: 指定したフィールドで結果を並べ替えます。
// 聚合查询示例 - $sort操作
List<Bson> pipeline = Arrays.asList(
Aggregates.match(Filters.eq("status", "active")),
Aggregates.sort(Sorts.descending("price"))
);
AggregateIterable<Document> results = collection.aggregate(pipeline);
上記の例では、$sort
この操作は「価格」フィールドで降順に並べ替えるために使用されます。
5. データモデルの設計とインデックス作成
データモデリングの原則
-
ドキュメントの設計: MongoDB はドキュメントを使用してデータを表現します。ドキュメントはリレーショナル データベースのレコードの行に似ています。ドキュメントを設計するときは、アプリケーションのクエリ ニーズを満たすためにドキュメント内の関連データを編成する方法を考慮する必要があります。
-
冗長データ: MongoDB は、クエリをより効率的に満たすことができるように、ドキュメントに冗長データを含めることを奨励します。これは、複数のテーブルを関連付けるのではなく、関連するデータを同じドキュメントに保存できることを意味します。冗長データを追加するかどうかを決定するときは、データの更新頻度とクエリのパフォーマンスを比較検討する必要があります。
-
埋め込みと参照: MongoDB では、関連データをドキュメントに埋め込むか、参照を使用して他のドキュメントを関連付けるかを選択できます。データを埋め込むとクエリのパフォーマンスが向上しますが、ドキュメントのサイズが増加します。参照を使用するとドキュメントのサイズを削減できますが、完全な情報を取得するには複数のクエリが必要になる場合があります。データとクエリ要件の間の関係に応じて、埋め込みの使用と参照の使用の間にはトレードオフがあります。
-
データの正規化: 従来のリレーショナル データベースとは異なり、MongoDB は厳密なデータの正規化を要求しません。データは、アプリケーションのニーズに応じてクエリに適した形式に編成できます。これは、さまざまなエンティティの関連情報を 1 つのドキュメントに保存して、クエリ時のデータ アクセスの数を減らすことができることを意味します。
-
クエリの最適化: データ モデルを設計するときは、一般的なクエリ操作を考慮し、それに応じてデータ構造とインデックスを最適化する必要があります。適切なフィールド インデックスを使用するとクエリのパフォーマンスが向上し、頻繁に使用されるデータを 1 つのドキュメントに配置するとクエリの数を減らすことができます。
-
スケーラビリティ: MongoDB は、シャーディング テクノロジを通じて水平拡張を実現できます。データ モデリングの際は、シャードのデプロイメントをサポートし、各シャードにデータを均等に分散するデータ モデルを設計する方法を検討できます。
-
データの整合性: MongoDB は、一意のインデックス、複合インデックス、検証ルールなどの一部のデータ整合性制約をサポートします。モデリング時にこれらの制約を使用して、データの整合性と一貫性を確保できます。
-
クエリ パターンを考慮する: データ モデルを設計するときは、頻繁に実行されるクエリ操作を考慮し、それに応じてデータ構造とクエリ パターンを最適化する必要があります。これには、特定の種類のクエリをサポートするために、異なるコレクションを作成するか、異なるインデックスを使用することが必要になる場合があります。
埋め込みと参照
MongoDB には、埋め込みと参照という 2 つの一般的なデータ編成方法があります。これら 2 つのアプローチには、データ モデリングにおけるアプリケーション シナリオと利点と欠点が異なります。
-
埋め込み:
- 埋め込みとは、あるドキュメントを別のドキュメント内に埋め込んで入れ子構造を形成することです。これは、ドキュメントに他のドキュメントの完全なコピーを含めることができることを意味します。
- アドバンテージ:
- パフォーマンスの向上: 関連データが同じドキュメントに保存されるため、すべての関連データを 1 回のクエリ操作で取得でき、複数のデータベース操作を回避できます。これにより、データ読み取り時に高いパフォーマンスを実現できます。
- データの局所性: 関連データが同じドキュメントに保存されるため、データの局所性が向上します。ドキュメントをロードする必要がある場合は、他のコレクションまたはドキュメントへのアクセスを減らします。
- 冗長データ: 関連データを複数のドキュメントにコピーして、頻繁なリレーショナル クエリ操作を回避できます。これにより、クエリのパフォーマンスが向上します。
- 欠点:
- 冗長データ: 埋め込み方法により、データが冗長に保存されます。埋め込みデータが変更された場合は、そのデータを使用しているすべてのドキュメントを更新する必要があります。
- データの整合性: 冗長データが存在するため、データの整合性の問題が発生する可能性があります。複数のドキュメントにわたる冗長データに一貫性がない場合、データの一貫性を保つために追加のロジックが必要になる場合があります。
-
参照:
- 参照は、フィールドを使用して他のドキュメントまたは参照への参照を保存するオブジェクト ID です。参照を通じて、異なるコレクションまたはドキュメント間の関係を確立できます。
- アドバンテージ:
- データの一貫性: 参照方法では、データの冗長性が回避され、データの一貫性が保証されます。参照データが変更された場合、更新は 1 回だけ必要です。
- ストレージスペース: 埋め込み方式と比較して、参照方式では完全な関連データを保存する必要がないため、ストレージスペースが節約されます。
- 欠点:
- クエリのパフォーマンス: 引用によってクエリ操作が増える可能性があり、特に参照文書に関連付けられた完全な情報を取得する場合には、追加のクエリ操作が必要になります。
- データ アクセスの遅延: 関連データをロードする必要がある場合、複数のクエリ操作が必要になる場合があり、データ アクセスの遅延が増加します。
- 複雑さ: 参照メソッドを使用する場合、関連付けクエリのロジックと参照データの解析を処理する必要があるため、コードが複雑になる可能性があります。
埋め込みまたは参照の選択は、特定のアプリケーションのシナリオと要件によって異なります。一般に、埋め込みは、頻繁に一緒に使用される関連データに適しており、クエリのパフォーマンスとデータの局所性を向上させることができます。参照は、より高いデータ一貫性要件があるシナリオ、または複雑なクエリ関連付け操作をサポートする必要があるシナリオに適しています。
索引
MongoDB インデックスは、クエリのパフォーマンスを向上させるために使用されるデータ構造であり、データベースの読み取り操作を高速化できます。インデックスを使用すると、コレクションの 1 つ以上のフィールドにデータ構造を作成することで、データベースがデータをより迅速に検索して取得できるようになります。
-
インデックスの種類:
- 単一フィールド インデックス: 1 つのフィールドのみにインデックスを作成します。
- 複合インデックス: 複数のフィールドに複合インデックスを作成します。
- テキストインデックス: 全文検索用。
- ハッシュインデックス: フィールドをハッシュします。
- 地理空間インデックス: 地理的に関連するデータを処理するために使用されます。
-
インデックスの原則:
- インデックスは、B ツリーやハッシュ テーブルなどのデータ構造に基づいており、フィールドの値をその物理的な記憶場所にマップします。
- インデックスはツリー構造を使用しているため、コレクション全体をスキャンしなくても、二分検索と同様のアルゴリズムを通じて対象となるレコードを迅速に見つけることができます。
-
インデックスの利点:
- クエリのパフォーマンスの向上: インデックスを使用すると、クエリ中のディスク I/O が削減され、データの読み取りが高速化されます。
- 高速ソート: インデックスをフィールドごとにソートして、ソート効率を向上させることができます。
- 一意の制約のサポート: フィールドの一意性は、一意のインデックスによって保証されます。
- カバーされたクエリのサポート: インデックスに必須フィールドを含めることで、実際のデータへのアクセスを回避します。
-
インデックスを作成します。
- MongoDB では、
createIndex()
というメソッドを使用してインデックスが作成されます。 - インデックス管理は、コマンド ライン ツール、MongoDB シェル、またはドライバーを使用して実行できます。
- MongoDB では、
-
インデックスの使用に関する注意:
- インデックスは一定量のストレージ領域を占有する必要があるため、インデックスの数とサイズを考慮する必要があります。
- 特定のクエリ モードとデータ アクセス方法に従って、適切なインデックスを設計する必要があります。
- インデックスは書き込み操作のパフォーマンスに一定の影響を与えるため、読み取りと書き込みのバランスを取る必要があります。
Javaの例
- 単一フィールド インデックスを作成する: 単一フィールド インデックスは最も単純なタイプのインデックスであり、1 つのフィールドのみにインデックスを作成します。
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.createIndex(Indexes.ascending("fieldName"));
- 複数のフィールド インデックスを作成する: 複数のフィールド インデックスを使用すると、複数のフィールドに複合インデックスを作成して、複合クエリをサポートできます。
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.createIndex(Indexes.compoundIndex(Indexes.ascending("field1"), Indexes.ascending("field2")));
- テキスト インデックスの作成: テキスト インデックスは全文検索に使用され、検索パフォーマンスを向上させるためにテキスト フィールドにインデックスを作成します。
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.createIndex(Indexes.text("textField"));
- ハッシュ インデックスを作成する: ハッシュ インデックスは均等に分散されたデータに適しており、インデックスはフィールドをハッシュすることによって作成されます。
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.createIndex(Indexes.hashed("fieldName"));
- 地理空間インデックスの作成: 地理空間インデックスは、地理的位置データの保存とクエリに使用されます。
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.createIndex(Indexes.geo2d("locationField"));
- 一意のインデックスを作成します。一意のインデックスによりフィールドの一意性が保証され、重複データの挿入を防ぐことができます。
MongoCollection<Document> collection = database.getCollection("myCollection");
collection.createIndex(Indexes.ascending("fieldName"), new IndexOptions().unique(true));
6. MongoDB のトランザクションと高可用性
Java での MongoDB トランザクション管理
Java では、MongoDB バージョン 4.0 でネイティブ トランザクション管理サポートが導入され始めました。MongoDB トランザクション管理を使用すると、開発者は複数の操作 (挿入、更新、削除など) を 1 つのアトミックな操作単位に結合し、同時に成功するかロールバックされるようにすることができます。
- トランザクションの作成:
トランザクションを使用する前に、トランザクション セッション ( ) オブジェクトを作成する必要がありますClientSession
。
ClientSession session = mongoClient.startSession();
- トランザクションを開始する:
トランザクション セッション オブジェクトを使用してトランザクションを開始し、startTransaction()
メソッドを呼び出してトランザクションを開始します。
session.startTransaction();
- トランザクション操作の実行:
トランザクションでは、操作のアトミック単位としてコミットまたはロールバックされる複数のデータベース操作を実行できます。
collection.insertOne(session, document); // 在事务中插入文档
collection.updateOne(session, filter, update); // 在事务中更新文档
collection.deleteOne(session, filter); // 在事务中删除文档
- トランザクションのコミット:
すべてのトランザクション操作が正常に実行された場合、commitTransaction()
メソッドを呼び出してトランザクションをコミットできます。
session.commitTransaction();
- トランザクションのロールバック:
エラーが発生した場合、またはトランザクションをキャンセルする必要がある場合、abortTransaction()
メソッドを呼び出してトランザクションをロールバックできます。
session.abortTransaction();
- トランザクションの終了:
トランザクションが完了したら、トランザクション セッション オブジェクトを閉じる必要があります。
session.close();
なお、トランザクション管理を使用するには、Mongoドライバーのバージョンが4.0以上で、MongoDBサーバーのレプリカセットが書き込み操作確認(書き込み懸念)機能を有効にしている必要があります。さらに、トランザクションは同じデータベース内の複数のコレクション間でも実行する必要があり、複数のデータベースにまたがることはできません。
レプリカ セットとレプリカ セット
レプリカ セット (レプリカ セット) は、データの冗長性と高可用性を提供するために MongoDB で使用されるメカニズムです。複数の MongoDB インスタンス間でデータをレプリケートすることでデータの冗長ストレージを実現し、プライマリ ノード (Primary) に障害が発生した場合に新しいプライマリ ノードを自動的に選択できるようにすることで、高可用性を実現します。
-
レプリカ セットの構成:
- プライマリ ノード (プライマリ): すべての書き込み操作を処理し、最新のデータを読み取ります。各レプリカ セットはプライマリ ノードを 1 つだけ持つことができます。
- スレーブ ノード (セカンダリ): マスター ノードにデータをコピーし、読み取りリクエストを処理します。複数のスレーブ ノードが存在する場合があります。
- アービター: 選挙で投票する役割を果たしますが、データは保存されません。アービトレータ ノードはデータ複製プロセスには参加しません。
-
レプリカ セットの仕組み:
- データ複製: マスターノードは書き込み操作を Oplog (操作ログ) に記録し、スレーブノードは Oplog 内の操作記録を読み取ることでデータを複製します。
- 障害回復: マスター ノードに障害が発生した場合、残りのスレーブ ノードは新しいマスター ノードを選択して、レプリカ セットが引き続き使用できるようにします。
- クライアント アクセス: クライアントは、書き込み操作のためにマスター ノードに直接接続して最新データを読み取ることも、読み取り操作のために任意のスレーブ ノードに接続することもできます。
-
レプリカセットの構成:
- レプリカ セットの初期化: レプリカ セットを作成するには、ノードの IP アドレス、ポート番号、レプリカ セット名を含む同じレプリカ セット構成をすべてのノードに設定する必要があります。
- 初期構成プロセス: 各ノードの MongoDB インスタンスを起動し、同じレプリカ セット構成を指定すると、ノードは自動的にレプリカ セットに参加します。
-
レプリカ セットのアプリケーション シナリオ:
- 冗長バックアップ: レプリカ セットは、データを異なるノードに複製することでデータの冗長バックアップを実現し、データのセキュリティと信頼性を向上させます。
- 高可用性: プライマリ ノードに障害が発生した場合、レプリカ セットは新しいプライマリ ノードを自動的に選択できるため、システムの高可用性が実現され、システムのダウンタイムが削減されます。
- 読み取り拡張: クライアントはスレーブ ノードで読み取り操作を実行し、マスター ノードの負荷を共有し、システムの同時処理能力を向上させることができます。
- 災害復旧: レプリカ セット内のノードに障害が発生した場合、障害が発生したノードを迅速に復旧して交換できます。