0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MongoDB 完全チートシート

Posted at

目次

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

MongoDBとは

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

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

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

インストール手順

  1. MongoDBのダウンロード:

  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クライアント
    • インストーラでチェックボックスをオンにするか、別途ダウンロード
  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):

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での設定:

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での設定:

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

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

アクセス制限の設定:

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での設定:

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は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

// インストール
// 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)

// インストール
// 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);
  }
})

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?