MongoDB 完全チートシート


## 目次
1. [MongoDBとは](#mongodbとは)
2. [インストールと設定 (Windows 11)](#インストールと設定-windows-11)
3. [基本概念](#基本概念)
4. [基本操作 (CRUD)](#基本操作-crud)
5. [高度なクエリ](#高度なクエリ)
6. [インデックス](#インデックス)
7. [集計フレームワーク](#集計フレームワーク)
8. [トランザクション](#トランザクション)
9. [バックアップとリストア](#バックアップとリストア)
10. [レプリケーションとシャーディング](#レプリケーションとシャーディング)
11. [セキュリティ](#セキュリティ)
12. [パフォーマンス最適化](#パフォーマンス最適化)
13. [Atlas (クラウドサービス)](#atlas-クラウドサービス)
14. [Node.jsとの連携](#nodejsとの連携)
15. [トラブルシューティング](#トラブルシューティング)
16. [参考リンク](#参考リンク)

## MongoDBとは

MongoDBは、ドキュメント指向のNoSQLデータベースです。JSONライクなBSONフォーマットでデータを保存し、スケーラビリティと柔軟性に優れています。

- **特徴**:
  - スキーマレス設計（柔軟なデータ構造）
  - 水平スケーリング
  - 高可用性
  - 地理空間インデックス
  - アグリゲーションフレームワーク

## インストールと設定 (Windows 11)

### インストール手順

1. **MongoDBのダウンロード**:
   - [MongoDB公式サイト](https://www.mongodb.com/try/download/community)からMongoDB Community Serverをダウンロード
   - 「Windows x64」版を選択

2. **インストーラの実行**:
   - ダウンロードしたMSIファイルを実行
   - 「Complete」インストールを選択
   - 「Install MongoDB as a Service」オプションにチェック
   - デフォルトのデータディレクトリ: `C:\Program Files\MongoDB\Server\[version]\data`
   - デフォルトのログディレクトリ: `C:\Program Files\MongoDB\Server\[version]\log`

3. **MongoDB Compassのインストール**:
   - MongoDBのGUIクライアント
   - インストーラでチェックボックスをオンにするか、[別途ダウンロード](https://www.mongodb.com/try/download/compass)

4. **環境変数の設定**:
   - システム環境変数のPathに以下を追加: `C:\Program Files\MongoDB\Server\[version]\bin`

5. **サービスの確認**:
   - サービス一覧で「MongoDB」が実行中であることを確認
   - または管理者権限のコマンドプロンプトで: `net start MongoDB`

### MongoDB Shellの起動

MongoDB Shell (mongosh)を使用してMongoDBサーバーに接続します：

```
mongosh
```

### データベースの基本コマンド

```
// データベース一覧表示
show dbs

// 使用するデータベースを選択/作成
use mydatabase

// 現在のデータベースを表示
db

// 現在のデータベースのコレクション一覧を表示
show collections
```

## 基本概念

### ドキュメント構造

MongoDBはドキュメント（JSONライクなBSON形式）でデータを保存します：

```
{
   "_id": ObjectId("60a6d595f462e23456789012"),
   "name": "山田太郎",
   "age": 30,
   "email": "yamada@example.com",
   "address": {
      "city": "東京",
      "zipcode": "123-4567"
   },
   "hobbies": ["読書", "旅行", "プログラミング"]
}
```

### 基本要素

- **データベース**: コレクションの集合
- **コレクション**: ドキュメントの集合（RDBのテーブルに相当）
- **ドキュメント**: 単一のレコード（JSONライクなBSON形式）
- **フィールド**: キーと値のペア（RDBの列に相当）
- **_id**: 各ドキュメントの一意の識別子

## 基本操作 (CRUD)

### 作成 (Create)

**単一ドキュメントの挿入**:
```
db.users.insertOne({
  name: "山田太郎", 
  age: 30, 
  email: "yamada@example.com"
})
```

**複数ドキュメントの挿入**:
```
db.users.insertMany([
  { name: "佐藤花子", age: 25, email: "sato@example.com" },
  { name: "鈴木一郎", age: 35, email: "suzuki@example.com" }
])
```

### 読み取り (Read)

**全ドキュメントの取得**:
```
db.users.find()
```

**整形して表示**:
```
db.users.find().pretty()
```

**条件付き検索**:
```
// 等価条件
db.users.find({ age: 30 })

// 比較演算子
db.users.find({ age: { $gt: 25 } })  // 25より大きい
db.users.find({ age: { $lt: 35 } })  // 35より小さい
db.users.find({ age: { $gte: 30 } }) // 30以上
db.users.find({ age: { $lte: 30 } }) // 30以下
db.users.find({ age: { $ne: 25 } })  // 25でない

// AND条件（複数条件を指定）
db.users.find({ age: 30, name: "山田太郎" })

// OR条件
db.users.find({ $or: [{ age: 30 }, { name: "佐藤花子" }] })

// 特定フィールドのみ取得
db.users.find({}, { name: 1, email: 1, _id: 0 })
```

**単一ドキュメントの取得**:
```
db.users.findOne({ name: "山田太郎" })
```

**件数制限と並べ替え**:
```
// 上位3件を取得
db.users.find().limit(3)

// 年齢の降順で並べ替え
db.users.find().sort({ age: -1 })

// 昇順で並べ替え
db.users.find().sort({ name: 1 })

// ページネーション（スキップと制限）
db.users.find().skip(10).limit(5)
```

**ドキュメント数のカウント**:
```
db.users.countDocuments({ age: { $gt: 25 } })
```

### 更新 (Update)

**単一ドキュメントの更新**:
```
db.users.updateOne(
  { name: "山田太郎" },
  { $set: { age: 31, updated_at: new Date() } }
)
```

**複数ドキュメントの更新**:
```
db.users.updateMany(
  { age: { $lt: 30 } },
  { $set: { status: "若手" } }
)
```

**更新演算子**:
```
// フィールド値の増加
db.users.updateOne({ name: "山田太郎" }, { $inc: { age: 1 } })

// 配列に要素を追加
db.users.updateOne({ name: "山田太郎" }, { $push: { hobbies: "料理" } })

// 配列から要素を削除
db.users.updateOne({ name: "山田太郎" }, { $pull: { hobbies: "料理" } })

// フィールドの名前変更
db.users.updateMany({}, { $rename: { "電話番号": "phone" } })

// 条件に合致する場合のみ更新（age < 30の場合のみ更新）
db.users.updateOne(
  { name: "山田太郎", age: { $lt: 30 } },
  { $set: { status: "若手" } }
)
```

**ドキュメントの置換**:
```
db.users.replaceOne(
  { name: "山田太郎" },
  { name: "山田太郎", age: 31, email: "newyamada@example.com" }
)
```

### 削除 (Delete)

**単一ドキュメントの削除**:
```
db.users.deleteOne({ name: "山田太郎" })
```

**複数ドキュメントの削除**:
```
db.users.deleteMany({ age: { $lt: 25 } })
```

**コレクション内の全ドキュメントを削除**:
```
db.users.deleteMany({})
```

**コレクションの削除**:
```
db.users.drop()
```

**データベースの削除**:
```
db.dropDatabase()
```

## 高度なクエリ

### 論理演算子

```
// AND (暗黙的)
db.users.find({ age: 30, city: "東京" })

// AND (明示的)
db.users.find({ $and: [{ age: 30 }, { city: "東京" }] })

// OR
db.users.find({ $or: [{ age: 30 }, { city: "大阪" }] })

// NOT
db.users.find({ age: { $not: { $gt: 30 } } })

// NOR (どの条件にも一致しない)
db.users.find({ $nor: [{ age: 30 }, { city: "大阪" }] })
```

### 配列クエリ

```
// 配列に特定の要素が含まれる
db.users.find({ hobbies: "読書" })

// 配列に複数の要素がすべて含まれる（順序は問わない）
db.users.find({ hobbies: { $all: ["読書", "旅行"] } })

// 配列の長さが特定の値
db.users.find({ "hobbies": { $size: 3 } })

// 配列の要素位置を指定
db.users.find({ "hobbies.0": "読書" })  // 最初の趣味が"読書"

// $elemMatch (配列内の要素が条件セットに一致)
db.orders.find({
  items: { $elemMatch: { name: "ノートPC", price: { $gt: 100000 } } }
})
```

### 正規表現検索

```
// "山田"で始まる名前
db.users.find({ name: /^山田/ })

// "gmail.com"で終わるメール
db.users.find({ email: /gmail\.com$/ })

// "技術"を含む趣味
db.users.find({ hobbies: /技術/ })

// 大文字小文字を区別しない検索
db.users.find({ name: /yamada/i })
```

### ネストされたドキュメントのクエリ

```
// ドット表記を使用したネストフィールドの検索
db.users.find({ "address.city": "東京" })

// ネストされたドキュメント全体の検索（完全一致）
db.users.find({
  address: { city: "東京", zipcode: "123-4567" }
})
```

### 存在チェック

```
// フィールドが存在する
db.users.find({ email: { $exists: true } })

// フィールドが存在しない
db.users.find({ phone: { $exists: false } })

// nullチェック（nullまたは存在しない）
db.users.find({ phone: null })

// 厳密なnullチェック（nullのみ）
db.users.find({ phone: { $type: 10 } })
```

### JavaScript式を使用したクエリ

```
// $where演算子（パフォーマンスに注意）
db.users.find({ $where: "this.hobbies.length > 3" })

// 関数を使用
db.users.find({ $where: function() { return this.age > 30 && this.hobbies.length > 2 } })
```

## インデックス

### インデックスの作成

```
// 単一フィールドのインデックス
db.users.createIndex({ name: 1 })  // 1:昇順、-1:降順

// 複合インデックス
db.users.createIndex({ name: 1, age: -1 })

// ユニークインデックス
db.users.createIndex({ email: 1 }, { unique: true })

// スパースインデックス（フィールドが存在するドキュメントのみインデックス）
db.users.createIndex({ phone: 1 }, { sparse: true })

// TTLインデックス（時間制限付きインデックス）
db.sessions.createIndex(
  { created_at: 1 },
  { expireAfterSeconds: 3600 }  // 1時間後に削除
)

// テキストインデックス
db.articles.createIndex({ title: "text", content: "text" })

// 地理空間インデックス
db.places.createIndex({ location: "2dsphere" })

// ハッシュインデックス（シャーディング用）
db.users.createIndex({ _id: "hashed" })

// バックグラウンドでインデックス作成
db.users.createIndex(
  { name: 1 },
  { background: true }
)
```

### インデックスの管理

```
// インデックス一覧の表示
db.users.getIndexes()

// インデックスのサイズと統計情報
db.users.stats().indexSizes

// 特定のインデックスを削除
db.users.dropIndex("name_1")

// すべてのインデックスを削除（_idを除く）
db.users.dropIndexes()

// インデックスを使用しているかチェック（実行計画）
db.users.find({ name: "山田太郎" }).explain()

// 詳細な実行計画
db.users.find({ name: "山田太郎" }).explain("executionStats")
```

## 集計フレームワーク

### 基本的な集計

```
// $match: ドキュメントのフィルタリング（WHERE句に相当）
db.users.aggregate([
  { $match: { age: { $gt: 30 } } }
])

// $group: グループ化と集計（GROUP BY句に相当）
db.users.aggregate([
  { $group: { _id: "$city", count: { $sum: 1 } } }
])

// $project: フィールドの選択と変換（SELECT句に相当）
db.users.aggregate([
  { $project: { name: 1, yearOfBirth: { $subtract: [2023, "$age"] } } }
])

// $sort: 結果の並べ替え（ORDER BY句に相当）
db.users.aggregate([
  { $sort: { age: -1 } }
])

// $limit: 結果の件数制限（LIMIT句に相当）
db.users.aggregate([
  { $limit: 5 }
])

// $skip: 結果のスキップ（OFFSET句に相当）
db.users.aggregate([
  { $skip: 10 }
])
```

### 高度な集計操作

```
// $unwind: 配列をフラット化
db.users.aggregate([
  { $unwind: "$hobbies" },
  { $group: { _id: "$hobbies", count: { $sum: 1 } } }
])

// $lookup: 他のコレクションとの結合（JOIN句に相当）
db.orders.aggregate([
  {
    $lookup: {
      from: "users",
      localField: "user_id",
      foreignField: "_id",
      as: "user_info"
    }
  }
])

// $facet: 複数の集計パイプラインを一度に実行
db.users.aggregate([
  {
    $facet: {
      "ageStats": [
        { $group: { _id: null, avg: { $avg: "$age" }, min: { $min: "$age" }, max: { $max: "$age" } } }
      ],
      "cityStats": [
        { $group: { _id: "$address.city", count: { $sum: 1 } } }
      ]
    }
  }
])

// $addFields: 既存のドキュメントに新しいフィールドを追加
db.users.aggregate([
  { $addFields: { fullName: { $concat: ["$firstName", " ", "$lastName"] } } }
])

// $bucket: 値をバケット（区間）に分類
db.users.aggregate([
  {
    $bucket: {
      groupBy: "$age",
      boundaries: [20, 30, 40, 50, 60],
      default: "Other",
      output: { count: { $sum: 1 } }
    }
  }
])
```

### 集計演算子

```
// 算術演算子
$add, $subtract, $multiply, $divide, $mod

// 文字列演算子
$concat, $substr, $toLower, $toUpper, $trim

// 日付演算子
$dayOfMonth, $month, $year, $hour, $minute, $second

// 比較演算子
$eq, $ne, $gt, $gte, $lt, $lte

// 配列演算子
$size, $arrayElemAt, $filter, $map, $reduce

// 条件演算子
$cond, $ifNull, $switch

// 型変換演算子
$toString, $toInt, $toDecimal, $toBool, $toDate
```

### 例：年齢層ごとの平均給料

```
db.employees.aggregate([
  { $match: { status: "active" } },
  {
    $group: {
      _id: {
        $switch: {
          branches: [
            { case: { $lt: ["$age", 30] }, then: "20代" },
            { case: { $lt: ["$age", 40] }, then: "30代" },
            { case: { $lt: ["$age", 50] }, then: "40代" }
          ],
          default: "50代以上"
        }
      },
      avgSalary: { $avg: "$salary" },
      count: { $sum: 1 }
    }
  },
  { $sort: { avgSalary: -1 } }
])
```

## トランザクション

MongoDBは4.0以降、マルチドキュメントトランザクションをサポートしています（レプリカセット環境が必要）。

### トランザクションの基本構文

```
// セッションの開始
const session = db.getMongo().startSession();

// トランザクションの開始
session.startTransaction();

try {
  // 操作1
  db.accounts.updateOne(
    { _id: "account1" },
    { $inc: { balance: -100 } },
    { session }
  );
  
  // 操作2
  db.accounts.updateOne(
    { _id: "account2" },
    { $inc: { balance: 100 } },
    { session }
  );
  
  // 操作3
  db.transactions.insertOne(
    { from: "account1", to: "account2", amount: 100, date: new Date() },
    { session }
  );
  
  // コミット
  session.commitTransaction();
} catch (error) {
  // エラー時はロールバック
  session.abortTransaction();
  print("Transaction aborted due to error: " + error);
} finally {
  // セッション終了
  session.endSession();
}
```

### トランザクションの注意点

- レプリカセットまたはシャードクラスタが必要
- タイムアウト制限がある（デフォルト60秒）
- パフォーマンスへの影響を考慮する
- ロックの競合に注意

## バックアップとリストア

### mongodumpによるバックアップ

```
// データベース全体のバックアップ
mongodump --out=C:\backup\mongodb\full

// 特定のデータベースのバックアップ
mongodump --db=mydatabase --out=C:\backup\mongodb\mydatabase

// 特定のコレクションのバックアップ
mongodump --db=mydatabase --collection=users --out=C:\backup\mongodb\users

// 圧縮バックアップ
mongodump --gzip --out=C:\backup\mongodb\compressed

// 認証が必要な場合
mongodump --username=admin --password=password --authenticationDatabase=admin --out=C:\backup\mongodb\auth
```

### mongorestoreによるリストア

```
// データベース全体のリストア
mongorestore C:\backup\mongodb\full

// 特定のデータベースのリストア
mongorestore --db=mydatabase C:\backup\mongodb\mydatabase\mydatabase

// 特定のコレクションのリストア
mongorestore --db=mydatabase --collection=users C:\backup\mongodb\users\mydatabase\users.bson

// 圧縮バックアップからのリストア
mongorestore --gzip C:\backup\mongodb\compressed

// ドロップオプション（リストア前にコレクションを削除）
mongorestore --drop C:\backup\mongodb\full
```

### mongoexport/mongoimport (JSONフォーマット)

```
// JSONエクスポート
mongoexport --db=mydatabase --collection=users --out=users.json

// CSVエクスポート
mongoexport --db=mydatabase --collection=users --type=csv --fields=name,email,age --out=users.csv

// JSONインポート
mongoimport --db=mydatabase --collection=users --file=users.json

// CSVインポート
mongoimport --db=mydatabase --collection=users --type=csv --headerline --file=users.csv
```

## レプリケーションとシャーディング

### レプリケーション (高可用性)

**レプリカセットの設定 (mongod.conf)**:
```yaml
replication:
  replSetName: "rs0"
```

**レプリカセットの初期化**:
```
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "server1:27017" },
    { _id: 1, host: "server2:27017" },
    { _id: 2, host: "server3:27017" }
  ]
})
```

**レプリカセットの管理**:
```
// 状態確認
rs.status()

// 設定確認
rs.conf()

// メンバー追加
rs.add("server4:27017")

// メンバー削除
rs.remove("server4:27017")

// セカンダリからの読み取り許可（注意：データの一貫性が保証されない）
db.setReadPreference("secondary")
```

### シャーディング (水平スケーリング)

**設定サーバーの起動**:
```
mongod --configsvr --replSet configRS --dbpath /data/configdb --port 27019
```

**シャードサーバーの起動**:
```
mongod --shardsvr --replSet shardRS1 --dbpath /data/shard1 --port 27018
```

**mongosルーターの起動**:
```
mongos --configdb configRS/config1:27019,config2:27019,config3:27019 --port 27017
```

**シャードの追加**:
```
sh.addShard("shardRS1/shard1:27018,shard2:27018,shard3:27018")
```

**データベースのシャーディング有効化**:
```
sh.enableSharding("mydatabase")
```

**コレクションのシャーディング**:
```
// ハッシュシャーディング
sh.shardCollection("mydatabase.users", { "_id": "hashed" })

// 範囲シャーディング
sh.shardCollection("mydatabase.orders", { "order_date": 1 })
```

**シャーディング状態の確認**:
```
sh.status()
```

## セキュリティ

### 認証と認可の有効化

**mongod.confでの設定**:
```yaml
security:
  authorization: enabled
```

### ユーザー管理

**管理者ユーザーの作成**:
```
use admin
db.createUser({
  user: "adminUser",
  pwd: "securePassword",
  roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
})
```

**データベース固有のユーザー作成**:
```
use mydatabase
db.createUser({
  user: "appUser",
  pwd: "appPassword",
  roles: [
    { role: "readWrite", db: "mydatabase" },
    { role: "read", db: "reporting" }
  ]
})
```

**ユーザー管理**:
```
// ユーザー一覧
db.getUsers()

// ユーザー情報
db.getUser("appUser")

// パスワード変更
db.changeUserPassword("appUser", "newPassword")

// ロールの追加
db.grantRolesToUser("appUser", [{ role: "readWrite", db: "newdb" }])

// ロールの削除
db.revokeRolesFromUser("appUser", [{ role: "readWrite", db: "newdb" }])

// ユーザー削除
db.dropUser("appUser")
```

### 組み込みロール

- **データベースユーザーロール**: `read`, `readWrite`
- **データベース管理ロール**: `dbAdmin`, `dbOwner`, `userAdmin`
- **クラスタ管理ロール**: `clusterAdmin`, `clusterManager`, `clusterMonitor`, `hostManager`
- **バックアップ/リストアロール**: `backup`, `restore`
- **全データベースロール**: `readAnyDatabase`, `readWriteAnyDatabase`, `userAdminAnyDatabase`, `dbAdminAnyDatabase`
- **スーパーユーザーロール**: `root`

### TLS/SSL設定

**mongod.confでの設定**:
```yaml
net:
  ssl:
    mode: requireSSL
    PEMKeyFile: /path/to/server.pem
    CAFile: /path/to/ca.pem
```

**クライアント接続**:
```
mongosh --ssl --sslCAFile /path/to/ca.pem --sslPEMKeyFile /path/to/client.pem
```

### ネットワークセキュリティ

**アクセス制限の設定**:
```yaml
net:
  bindIp: 127.0.0.1,192.168.1.100
```

**ファイアウォール設定**（Windowsファイアウォール）:
```
netsh advfirewall firewall add rule name="MongoDB" dir=in action=allow protocol=TCP localport=27017
```

## パフォーマンス最適化

### インデックス最適化

```
// ヒント（特定のインデックスを使用するよう指示）
db.users.find({ name: "山田太郎" }).hint({ name: 1 })

// カバリングインデックス（インデックスだけで検索が完結）
db.users.find({ name: "山田太郎" }, { name: 1, age: 1, _id: 0 }).hint({ name: 1, age: 1 })

// インデックスの利用状況分析
db.users.aggregate([
  { $indexStats: {} }
])
```

### クエリ最適化

```
// 不要なフィールドを除外
db.users.find({}, { huge_field: 0 })

// プロジェクション（必要なフィールドのみ取得）
db.users.find({}, { name: 1, email: 1, _id: 0 })

// ページネーション
db.users.find().skip(100).limit(20)

// 適切なソートキー（インデックスがあるフィールドでソート）
db.users.find().sort({ indexed_field: 1 })
```

### 読み取りパフォーマンス

```
// 読み取り設定
db.setReadPreference("secondary")  // セカンダリからの読み取り

// 読み取り操作の分離
db.setReadConcern("local")  // 読み取り一貫性レベル
```

### 書き込みパフォーマンス

```
// バルク書き込み
const bulkOp = db.users.initializeUnorderedBulkOp();
bulkOp.insert({ name: "田中一郎", age: 25 });
bulkOp.find({ name: "山田太郎" }).updateOne({ $set: { age: 32 } });
bulkOp.find({ age: { $lt: 20 } }).remove();
bulkOp.execute();

// 書き込み確認レベル
db.users.insertOne(
  { name: "新規ユーザー" },
  { writeConcern: { w: "majority", wtimeout: 5000 } }
)
```

### システムリソース最適化

**mongod.confでの設定**:
```yaml
storage:
  wiredTiger:
    engineConfig:
      cacheSizeGB: 4  # RAMの50%程度を推奨

net:
  maxIncomingConnections: 500  # 同時接続数制限

operationProfiling:
  slowOpThresholdMs: 100  # スロークエリのログ閾値
```

### パフォーマンスモニタリング

```
// サーバーステータス
db.serverStatus()

// データベースステータス
db.stats()

// コレクションステータス
db.users.stats()

// プロファイリング有効化
db.setProfilingLevel(1, 100)  // 100ms以上のクエリをログ

// プロファイルデータ確認
db.system.profile.find().sort({ ts: -1 }).limit(10)
```

## Atlas (クラウドサービス)

[MongoDB Atlas](https://www.mongodb.com/cloud/atlas)はMongoDBの公式マネージドクラウドサービスです。

### 主な機能

- スケーラブルなクラスタデプロイ
- 自動バックアップとポイントインタイムリカバリ
- パフォーマンスアドバイザー
- データレイク統合
- セキュリティ機能（VPC、暗号化など）
- グローバルクラスタ（低レイテンシグローバル書き込み）

### 接続方法

```
// 接続文字列の例
mongodb+srv://username:password@cluster0.mongodb.net/mydatabase

// MongoShellでの接続
mongosh "mongodb+srv://cluster0.mongodb.net/mydatabase" --username username
```

## Node.jsとの連携

### MongoDB Node.js Driver

```javascript
// インストール
// npm install mongodb

// 接続とクエリの例
const { MongoClient } = require('mongodb');

// 接続URL
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);

async function main() {
  try {
    // 接続
    await client.connect();
    console.log('MongoDB に接続しました');
    
    // データベースとコレクションの取得
    const db = client.db('mydatabase');
    const collection = db.collection('users');
    
    // ドキュメントの挿入
    const insertResult = await collection.insertOne({
      name: '山田太郎',
      age: 30,
      email: 'yamada@example.com'
    });
    console.log('挿入されたID:', insertResult.insertedId);
    
    // ドキュメントの検索
    const findResult = await collection.find({ age: { $gt: 25 } }).toArray();
    console.log('検索結果:', findResult);
    
    // ドキュメントの更新
    const updateResult = await collection.updateOne(
      { name: '山田太郎' },
      { $set: { age: 31 } }
    );
    console.log('更新されたドキュメント数:', updateResult.modifiedCount);
    
    // ドキュメントの削除
    const deleteResult = await collection.deleteOne({ name: '山田太郎' });
    console.log('削除されたドキュメント数:', deleteResult.deletedCount);
    
    // 集計
    const aggregationResult = await collection.aggregate([
      { $match: { age: { $gt: 20 } } },
      { $group: { _id: null, averageAge: { $avg: '$age' } } }
    ]).toArray();
    console.log('平均年齢:', aggregationResult[0]?.averageAge);
    
  } finally {
    // 接続を閉じる
    await client.close();
  }
}

main().catch(console.error);
```

### Mongoose (ODM)

```javascript
// インストール
// npm install mongoose

// 基本的な使用例
const mongoose = require('mongoose');

// 接続
mongoose.connect('mongodb://localhost:27017/mydatabase', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

// 接続イベント
mongoose.connection.on('connected', () => {
  console.log('Mongoose接続完了');
});

mongoose.connection.on('error', (err) => {
  console.log('Mongoose接続エラー: ' + err);
});

// スキーマ定義
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true
  },
  age: {
    type: Number,
    min: 0,
    max: 120
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  isActive: {
    type: Boolean,
    default: true
  },
  hobbies: [String],
  address: {
    city: String,
    zipcode: String
  }
});

// メソッド追加
userSchema.methods.getFullProfile = function() {
  return `${this.name} (${this.age}歳) - ${this.email}`;
};

// 静的メソッド
userSchema.statics.findByName = function(name) {
  return this.find({ name: new RegExp(name, 'i') });
};

// 仮想プロパティ
userSchema.virtual('isAdult').get(function() {
  return this.age >= 20;
});

// ミドルウェア（フック）
userSchema.pre('save', function(next) {
  console.log(`${this.name}を保存します`);
  next();
});

// モデル作成
const User = mongoose.model('User', userSchema);

// CRUD操作
async function mongooseExample() {
  try {
    // 作成
    const user = new User({
      name: '山田太郎',
      email: 'yamada@example.com',
      age: 30,
      hobbies: ['読書', '旅行'],
      address: {
        city: '東京',
        zipcode: '123-4567'
      }
    });
    
    await user.save();
    console.log('ユーザーが保存されました');
    
    // 読み取り
    const users = await User.find({ age: { $gt: 25 } })
      .select('name email age')
      .sort({ age: -1 })
      .limit(10);
    console.log('検索結果:', users);
    
    // 特定のIDで検索
    const userById = await User.findById(user._id);
    console.log('ID検索結果:', userById);
    
    // 更新
    const updateResult = await User.updateOne(
      { name: '山田太郎' },
      { $set: { age: 31 } }
    );
    console.log('更新結果:', updateResult);
    
    // 検索と更新を一度に
    const updatedUser = await User.findOneAndUpdate(
      { name: '山田太郎' },
      { $set: { age: 32 } },
      { new: true }  // 更新後のドキュメントを返す
    );
    console.log('更新されたユーザー:', updatedUser);
    
    // 削除
    const deleteResult = await User.deleteOne({ name: '山田太郎' });
    console.log('削除結果:', deleteResult);
    
    // 集計
    const aggregateResult = await User.aggregate([
      { $match: { age: { $gt: 20 } } },
      { $group: { _id: '$address.city', count: { $sum: 1 }, avgAge: { $avg: '$age' } } },
      { $sort: { count: -1 } }
    ]);
    console.log('集計結果:', aggregateResult);
    
  } catch (err) {
    console.error('エラー:', err);
  } finally {
    mongoose.connection.close();
  }
}

mongooseExample();
```

## トラブルシューティング

### 一般的な問題と解決策

1. **接続エラー**
   ```
   // 接続先が正しいか確認
   netstat -an | findstr 27017
   
   // MongoDBサービスが起動しているか確認
   net start | findstr MongoDB
   
   // 手動で起動
   net start MongoDB
   ```

2. **認証エラー**
   ```
   // 正しい認証データベースを指定
   mongosh -u username -p password --authenticationDatabase admin
   
   // 一時的に認証を無効化して回復
   // mongod.conf の security.authorization を disabled に変更
   ```

3. **パフォーマンス低下**
   ```
   // スロークエリログを確認
   db.setProfilingLevel(1, 100)  // 100ms以上のクエリをログ
   db.system.profile.find().sort({ ts: -1 })
   
   // インデックスの確認と作成
   db.collection.getIndexes()
   db.collection.createIndex({ frequently_queried_field: 1 })
   
   // メモリ使用量の確認
   db.serverStatus().wiredTiger.cache
   ```

4. **ディスク容量不足**
   ```
   // データベースサイズの確認
   db.stats()
   
   // コレクションサイズの確認
   db.collection.stats()
   
   // 古いデータを削除またはアーカイブ
   db.old_collection.drop()
   ```

5. **レプリケーション問題**
   ```
   // レプリカセットの状態確認
   rs.status()
   
   // プライマリの確認
   db.isMaster()
   
   // 同期状態の確認
   db.printReplicationInfo()
   ```

### ログファイルの確認

Windows環境のデフォルトログの場所：
```
C:\Program Files\MongoDB\Server\[version]\log\mongod.log
```

主要なログレベル：
- `F` (Fatal)
- `E` (Error)
- `W` (Warning)
- `I` (Informational)
- `D` (Debug)

### データ修復とリカバリ

```
// DBパスをバックアップ
xcopy C:\data\db C:\data\db_backup /E /I

// チェックと修復（非推奨：バックアップ後に実行）
mongod --dbpath C:\data\db --repair

// 破損したコレクションのリカバリ
// 1. バックアップからのリストア
// 2. コレクションをクローン
db.createCollection("users_new")
db.users.find().forEach(function(doc) {
  try {
    db.users_new.insertOne(doc);
  } catch (e) {
    print("Error inserting document: " + e);
  }
})
```

## 参考リンク

- [MongoDB公式ドキュメント](https://docs.mongodb.com/)
- [MongoDB University（無料オンラインコース）](https://university.mongodb.com/)
- [MongoDB GitHub](https://github.com/mongodb/mongo)
- [MongoDB日本語コミュニティ](https://jp.mongodb.com/community)
- [MongoDB ブログ](https://www.mongodb.com/blog)