# 機能設計書 14-MongoDB アダプター

## 概要

本ドキュメントは、Payload CMSにおけるMongoDB アダプター（`@payloadcms/db-mongodb`）の設計を定義する。MongoDBデータベースとの接続、CRUD操作、トランザクション管理、スキーマ生成を提供する。

### 本機能の処理概要

MongoDB アダプターは、Payload CMSとMongoDBデータベース間のインターフェースを提供するデータベースアダプターである。Mongoose ORMを使用してMongoDBへの接続とスキーマ管理を行い、PayloadのOperations層からのデータ操作要求をMongoDBクエリに変換して実行する。

**業務上の目的・背景**：MongoDBは柔軟なドキュメント指向データベースであり、スキーマレスな特性によりCMSの多様なコンテンツ構造に適している。レプリカセット構成によるトランザクションサポート、地理空間インデックス、全文検索など、CMSに必要な機能を提供する。Payload CMSのデフォルトデータベースとして、開発環境でのインメモリサーバー（MongoDB Memory Server）サポートも含む。

**機能の利用シーン**：
- 本番環境でのMongoDBクラスター接続
- 開発環境でのMongoDB Memory Serverによる軽量テスト
- レプリカセット構成でのトランザクション処理
- 地理空間クエリ（near演算子）の実行
- AWS DocumentDB、Azure Cosmos DBなどのMongoDB互換サービス対応

**主要な処理内容**：
1. 接続管理：MongoDB接続の確立、切断、再接続
2. スキーマ生成：Payloadフィールド定義からMongooseスキーマを自動生成
3. CRUD操作：create、find、findOne、update、delete
4. トランザクション：セッション管理、コミット、ロールバック
5. クエリ変換：PayloadのWhere条件をMongoDBクエリに変換
6. マイグレーション：スキーマ変更のマイグレーション実行

**関連システム・外部連携**：
- MongoDB / MongoDB Atlas
- MongoDB Memory Server（開発・テスト用）
- AWS DocumentDB、Azure Cosmos DB（互換サービス）
- Mongoose ORM

**権限による制御**：
- MongoDB接続文字列での認証
- データベースユーザー権限に基づくアクセス制御

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （該当なし） | - | データベース層のため画面連携なし |

## 機能種別

データベースアダプター / ORM統合

## 入力仕様

### アダプター設定パラメータ

| パラメータ名 | 型 | 必須 | 説明 | デフォルト |
|-------------|-----|-----|------|-----------|
| url | string / false | Yes | MongoDB接続URL | - |
| connectOptions | ConnectOptions | No | Mongoose接続オプション | {} |
| autoPluralization | boolean | No | コレクション名の自動複数形化 | true |
| allowIDOnCreate | boolean | No | create時にカスタムIDを許可 | false |
| allowAdditionalKeys | boolean | No | スキーマ外のキーを許可 | false |
| transactionOptions | TransactionOptions / false | No | トランザクションオプション | {} |
| collation | CollationOptions | No | 照合順序設定 | undefined |
| ensureIndexes | boolean | No | 起動時にインデックス作成を待機 | false |
| disableIndexHints | boolean | No | インデックスヒント無効化 | false |
| disableFallbackSort | boolean | No | フォールバックソート無効化 | false |
| bulkOperationsSingleTransaction | boolean | No | 一括操作を個別トランザクションで実行 | false |
| useAlternativeDropDatabase | boolean | No | 代替dropDatabase実装使用 | false |
| useBigIntForNumberIDs | boolean | No | 数値IDにBigInt使用 | false |
| useJoinAggregations | boolean | No | JOIN時に集約を使用 | true |
| usePipelineInSortLookup | boolean | No | ソート時のパイプライン使用 | true |
| migrationDir | string | No | マイグレーションディレクトリ | 自動検出 |
| mongoMemoryServer | MongoMemoryReplSet | No | インメモリサーバーインスタンス | - |
| collectionsSchemaOptions | Record | No | コレクション別スキーマオプション | {} |
| afterCreateConnection | function | No | 接続作成後のコールバック | - |
| afterOpenConnection | function | No | 接続オープン後のコールバック | - |

### CRUD操作パラメータ

各CRUD操作はPayload共通のインターフェースに従う。詳細はREST API機能設計書を参照。

## 出力仕様

### 出力データ

PayloadのドキュメントフォーマットでJSON形式のデータを返却。

### 出力先

- Operations層への戻り値
- MongoDBデータベース（書き込み操作時）

## 処理フロー

### 初期化処理シーケンス

```
1. mongooseAdapter()呼び出し
   └─ アダプター設定オブジェクトを受け取る

2. createDatabaseAdapter()
   └─ 共通アダプターインターフェースでラップ

3. init()実行
   └─ Mongooseコネクション作成（未接続状態）
   └─ コレクションごとにスキーマ生成
   └─ バージョン管理用スキーマ生成
   └─ グローバルモデル生成

4. connect()実行
   └─ mongoose.createConnection()で接続確立
   └─ レプリカセット確認（トランザクション対応）
   └─ 必要に応じてインデックス作成
   └─ 本番環境でマイグレーション実行
```

### CRUD操作シーケンス（create）

```
1. create()呼び出し
   └─ collection、data、req等を受け取る

2. getCollection()
   └─ コレクションモデルと設定を取得

3. transform() - write
   └─ Payloadデータ形式をMongoDBドキュメント形式に変換

4. カスタムID処理
   └─ _idフィールドの設定

5. getSession()
   └─ トランザクションセッション取得

6. Model.create()
   └─ MongoDBへドキュメント作成

7. transform() - read
   └─ MongoDBドキュメントをPayloadデータ形式に変換

8. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[mongooseAdapter設定] --> B[createDatabaseAdapter]
    B --> C[init実行]
    C --> D[スキーマ生成]
    D --> E[モデル登録]
    E --> F[connect実行]
    F --> G{レプリカセット?}
    G -->|Yes| H[トランザクション有効]
    G -->|No| I[トランザクション無効]
    H --> J[接続完了]
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトIDタイプ | defaultIDTypeは'text'（MongoDB ObjectId文字列） | 全コレクション |
| BR-02 | トランザクション要件 | レプリカセット構成時のみトランザクション有効 | transactionOptions設定時 |
| BR-03 | 自動複数形化 | コレクション名をMongooseの規則で自動複数形化 | autoPluralization=true時 |
| BR-04 | createdAtデフォルト | create時にcreatedAtが未設定なら現在時刻を設定 | create操作 |
| BR-05 | インデックスヒント | countDocumentsで_idインデックスをヒント指定 | disableIndexHints=false時 |
| BR-06 | フォールバックソート | ソートフィールドが非一意の場合createdAtで二次ソート | disableFallbackSort=false時 |

### 計算ロジック

**推定カウント使用判定**:
- フィルタ条件がない場合は`useEstimatedCount: true`（高速だが概算）
- フィルタ条件がある場合は実カウント

## データベース操作仕様

### 操作別MongoDB実行内容

| Payload操作 | MongoDB操作 | 備考 |
|------------|------------|------|
| create | Model.create() | 単一ドキュメント作成 |
| find | Model.paginate() | mongoose-paginate-v2使用 |
| findOne | Model.findOne() | 単一ドキュメント取得 |
| updateOne | Model.updateOne() | 単一ドキュメント更新 |
| updateMany | Model.updateMany() | 複数ドキュメント更新 |
| deleteOne | Model.deleteOne() | 単一ドキュメント削除 |
| deleteMany | Model.deleteMany() | 複数ドキュメント削除 |
| count | Model.countDocuments() | ドキュメント数カウント |
| upsert | Model.findOneAndUpdate() | upsert: true |
| queryDrafts | aggregate() | バージョンコレクションから最新ドラフト取得 |

### クエリ変換

PayloadのWhere条件は`buildQuery`でMongoDBクエリに変換される：

| Payload演算子 | MongoDB演算子 |
|--------------|--------------|
| equals | { field: value } |
| not_equals | { $ne: value } |
| greater_than | { $gt: value } |
| greater_than_equal | { $gte: value } |
| less_than | { $lt: value } |
| less_than_equal | { $lte: value } |
| in | { $in: [...] } |
| not_in | { $nin: [...] } |
| like | { $regex: /.../, $options: 'i' } |
| contains | { $regex: /.../ } |
| exists | { $exists: true/false } |
| near | { $near: { $geometry: {...} } } |
| and | { $and: [...] } |
| or | { $or: [...] } |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E11000 | DuplicateKey | 一意制約違反 | handleErrorでUniqueConstraintErrorに変換 |
| ENOTFOUND | 接続エラー | MongoDB接続失敗 | 接続URLを確認 |
| MongoNetworkError | ネットワークエラー | ネットワーク断 | ネットワーク設定を確認 |
| ValidationError | バリデーションエラー | スキーマ検証失敗 | データ形式を確認 |

### リトライ仕様

MongoDBドライバーの自動再接続機能に依存。明示的なリトライ実装なし。

## トランザクション仕様

### トランザクション管理

- `beginTransaction`: ClientSessionを開始し、req.transactionIDに格納
- `commitTransaction`: セッションをコミットしてリソース解放
- `rollbackTransaction`: セッションをアボートしてリソース解放
- `getSession`: req.transactionIDからセッションを取得

### 注意事項

- レプリカセット構成でのみトランザクション有効
- `transactionOptions: false`でトランザクション無効化
- `bulkOperationsSingleTransaction: true`で一括操作を個別トランザクションに分割（DocumentDB対応）

## パフォーマンス要件

- `useEstimatedCount`によるカウント最適化
- インデックスヒントによるcountDocuments高速化
- `useJoinAggregations`による集約パイプラインでのJOIN
- `usePipelineInSortLookup`によるソート時の$lookup最適化

## セキュリティ考慮事項

- 接続URLでの認証（ユーザー名/パスワード）
- TLS/SSL接続オプション
- MongoDB認証・認可機能の活用
- 本番環境での接続文字列の秘匿

## 備考

- MongoDB 3.4以上でcollationサポート
- MongoDB Memory Serverは開発・テスト専用
- AWS DocumentDB、Azure Cosmos DB使用時は互換性オプション確認

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、MongoDBアダプターの型定義とインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/db-mongodb/src/index.ts` | Args型、MongooseAdapter型の定義（69-211行目） |
| 1-2 | types.ts | `packages/db-mongodb/src/types.ts` | CollectionModel、GlobalModel、BuildSchemaOptions型の定義 |

**読解のコツ**: `Args`型でアダプター設定オプションを定義、`MongooseAdapter`型でアダプターインスタンスの構造を定義。`declare module 'payload'`でPayloadの`DatabaseAdapter`型を拡張している。

#### Step 2: エントリーポイントを理解する

アダプター生成のメイン関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/db-mongodb/src/index.ts` | mongooseAdapter関数（252-357行目） |

**主要処理フロー**:
- **252-274行目**: 引数のデストラクチャリングとデフォルト値設定
- **275行目**: 内部adapter関数の定義
- **277行目**: mongoose.set('strictQuery', false)でMongoose設定
- **279-348行目**: createDatabaseAdapterでアダプターオブジェクト生成
- **319行目**: `defaultIDType: 'text'`（ObjectId文字列）
- **307行目**: レプリカセットなし時はdefaultBeginTransaction使用
- **351-356行目**: DatabaseAdapterObjを返却

#### Step 3: 初期化処理を理解する

init関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | init.ts | `packages/db-mongodb/src/init.ts` | init関数 |

**主要処理フロー**:
- **24行目**: Mongooseコネクション作成（未オープン）
- **30-81行目**: 各コレクションのスキーマ生成とモデル登録
- **34-70行目**: バージョン管理有効時のバージョンスキーマ生成
- **72-80行目**: コレクションモデル登録
- **83行目**: グローバルモデル生成
- **85-117行目**: グローバルバージョンスキーマ生成

#### Step 4: 接続処理を理解する

connect関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | connect.ts | `packages/db-mongodb/src/connect.ts` | connect関数 |

**主要処理フロー**:
- **17-19行目**: url=falseの場合は接続スキップ
- **38-43行目**: mongoose.createConnectionで接続確立
- **45行目**: openUriで接続オープン
- **51-69行目**: useAlternativeDropDatabaseの実装（Firestore対応）
- **73-78行目**: MongoDB Memory Server使用時の待機
- **80-83行目**: レプリカセットなし時はトランザクション無効化
- **86-91行目**: PAYLOAD_DROP_DATABASE環境変数でDB削除
- **94-100行目**: ensureIndexesオプションでインデックス作成

#### Step 5: CRUD操作を理解する

create、find関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | create.ts | `packages/db-mongodb/src/create.ts` | create関数 |
| 5-2 | find.ts | `packages/db-mongodb/src/find.ts` | find関数 |

**主要処理フロー**（create.ts）:
- **16行目**: getCollectionでモデルと設定取得
- **20-22行目**: createdAtのデフォルト値設定
- **24-29行目**: transform (write) でデータ変換
- **31-48行目**: カスタムID処理（_id設定）
- **50-54行目**: セッション取得とオプション設定
- **57行目**: Model.createでドキュメント作成
- **67-72行目**: transform (read) で結果変換

**主要処理フロー**（find.ts）:
- **35行目**: getCollectionでモデル取得
- **39-42行目**: near制約の検出
- **48-57行目**: buildSortParamでソート条件構築
- **59-65行目**: buildQueryでMongoDBクエリ構築
- **67行目**: getSessionでセッション取得
- **71-82行目**: paginationOptions設定
- **129-138行目**: buildJoinAggregationでJOIN集約構築
- **140-158行目**: aggregatePaginateまたはModel.paginate実行
- **170-175行目**: transform (read) で結果変換

#### Step 6: クエリ変換を理解する

buildQuery関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | buildQuery.ts | `packages/db-mongodb/src/queries/buildQuery.ts` | buildQuery関数 |
| 6-2 | operatorMap.ts | `packages/db-mongodb/src/queries/operatorMap.ts` | 演算子マッピング |

### プログラム呼び出し階層図

```
Operations層 (payload.db.create/find/update/delete)
    │
    └─ MongoDB Adapter
           │
           ├─ create.ts
           │      ├─ getCollection()
           │      ├─ transform() [write]
           │      ├─ getSession()
           │      ├─ Model.create()
           │      └─ transform() [read]
           │
           ├─ find.ts
           │      ├─ getCollection()
           │      ├─ buildSortParam()
           │      ├─ buildQuery()
           │      ├─ getSession()
           │      ├─ buildJoinAggregation()
           │      ├─ aggregatePaginate() / Model.paginate()
           │      └─ transform() [read]
           │
           └─ transactions/
                  ├─ beginTransaction.ts
                  ├─ commitTransaction.ts
                  └─ rollbackTransaction.ts
```

### データフロー図

```
[Payload Operations]           [MongoDB Adapter]           [MongoDB]

payload.db.create() ───▶ transform (write) ───▶ Model.create()
                                  │                    │
                                  │                    ▼
                                  │             MongoDB Insert
                                  │                    │
                    ◀─────── transform (read) ◀────────┘
                                  │
                                  ▼
                           Document (Payload形式)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/db-mongodb/src/index.ts` | ソース | アダプターエントリーポイント |
| types.ts | `packages/db-mongodb/src/types.ts` | ソース | 型定義 |
| connect.ts | `packages/db-mongodb/src/connect.ts` | ソース | MongoDB接続処理 |
| init.ts | `packages/db-mongodb/src/init.ts` | ソース | 初期化処理 |
| destroy.ts | `packages/db-mongodb/src/destroy.ts` | ソース | 切断処理 |
| create.ts | `packages/db-mongodb/src/create.ts` | ソース | ドキュメント作成 |
| find.ts | `packages/db-mongodb/src/find.ts` | ソース | ドキュメント検索 |
| findOne.ts | `packages/db-mongodb/src/findOne.ts` | ソース | 単一ドキュメント取得 |
| updateOne.ts | `packages/db-mongodb/src/updateOne.ts` | ソース | 単一ドキュメント更新 |
| updateMany.ts | `packages/db-mongodb/src/updateMany.ts` | ソース | 複数ドキュメント更新 |
| deleteOne.ts | `packages/db-mongodb/src/deleteOne.ts` | ソース | 単一ドキュメント削除 |
| deleteMany.ts | `packages/db-mongodb/src/deleteMany.ts` | ソース | 複数ドキュメント削除 |
| count.ts | `packages/db-mongodb/src/count.ts` | ソース | ドキュメント数カウント |
| upsert.ts | `packages/db-mongodb/src/upsert.ts` | ソース | Upsert操作 |
| queryDrafts.ts | `packages/db-mongodb/src/queryDrafts.ts` | ソース | ドラフトクエリ |
| buildQuery.ts | `packages/db-mongodb/src/queries/buildQuery.ts` | ソース | クエリ構築 |
| buildSortParam.ts | `packages/db-mongodb/src/queries/buildSortParam.ts` | ソース | ソート構築 |
| operatorMap.ts | `packages/db-mongodb/src/queries/operatorMap.ts` | ソース | 演算子マッピング |
| transform.ts | `packages/db-mongodb/src/utilities/transform.ts` | ソース | データ変換 |
| getSession.ts | `packages/db-mongodb/src/utilities/getSession.ts` | ソース | セッション取得 |
| beginTransaction.ts | `packages/db-mongodb/src/transactions/beginTransaction.ts` | ソース | トランザクション開始 |
| commitTransaction.ts | `packages/db-mongodb/src/transactions/commitTransaction.ts` | ソース | トランザクションコミット |
| rollbackTransaction.ts | `packages/db-mongodb/src/transactions/rollbackTransaction.ts` | ソース | トランザクションロールバック |
| buildCollectionSchema.ts | `packages/db-mongodb/src/models/buildCollectionSchema.ts` | ソース | コレクションスキーマ生成 |
| buildSchema.ts | `packages/db-mongodb/src/models/buildSchema.ts` | ソース | スキーマ生成共通 |
