CheatSheet
日本語 icon日本語English iconEnglish
チートシートとはカンニングペーパーのことです。それが転じて、本来覚えることをまとめておいたものです。
要点をすぐに参照できるようにまとめてみました。

MongoDB

エンジニアのためのWebチートシート

MongoDBは、ドキュメント指向のNoSQLデータベースです。 JSON風のドキュメントを柔軟に格納でき、スケーラビリティに優れています。 CRUD操作、クエリ・更新演算子、集約パイプライン、インデックス、データモデリングなどをチートシートにまとめました。

mongosh コマンド

接続

  • mongosh でデータベースに接続する方法です。

    # ローカル接続(localhost:27017)
    mongosh
    
    # URI指定
    mongosh "mongodb://localhost:27017/mydb"
    
    # ユーザー認証付き
    mongosh "mongodb://user:pass@host:27017/mydb"
    
    # MongoDB Atlas
    mongosh "mongodb+srv://cluster.mongodb.net/mydb" \
      --username myuser

データベース & コレクション

  • データベースとコレクションの操作です。

    // データベース操作
    show dbs                      // DB一覧
    db                            // 現在のDB名
    use myDatabase                // DB切替(なければ作成)
    db.dropDatabase()             // DB削除
    
    // コレクション操作
    show collections              // コレクション一覧
    db.createCollection("users")  // 作成
    db.users.drop()               // 削除
    db.users.renameCollection("members") // 名前変更

ヘルパーコマンド

  • よく使うヘルパーメソッドです。

    // 統計情報
    db.stats()                    // DB統計
    db.users.stats()              // コレクション統計
    db.serverStatus()             // サーバー状態
    
    // カウント
    db.users.countDocuments({})
    db.users.estimatedDocumentCount()
    
    // Distinct(ユニーク値)
    db.users.distinct("status")
    
    // ファイル実行
    load("script.js")
    
    // 終了
    quit()

CRUD操作

Create(作成)

  • ドキュメントの挿入です。

    // 1件挿入
    db.users.insertOne({
      name: "Alice", email: "alice@example.com",
      age: 30, tags: ["developer", "mongodb"],
      createdAt: new Date()
    })
    // 複数挿入
    db.users.insertMany([
      { name: "Bob", age: 25, status: "active" },
      { name: "Charlie", age: 35, status: "active" }
    ])
    // ordered: false で重複エラーをスキップして続行
    db.users.insertMany(
      [{ _id: 1, name: "A" }, { _id: 1, name: "B" }, { _id: 2, name: "C" }],
      { ordered: false }
    )

Read(読み取り)

  • ドキュメントの検索です。

    db.users.find()                     // 全件取得
    db.users.find({ age: { $gt: 25 } }) // 条件付き
    db.users.findOne({ name: "Alice" }) // 1件のみ
    // プロジェクション(フィールド選択)
    db.users.find({}, { name: 1, email: 1, _id: 0 })
    
    // ソート・スキップ・リミット
    db.users.find()
      .sort({ age: -1 }).skip(10).limit(5)

Update & Delete

  • updateOne / updateMany

    db.users.updateOne(
      { name: "Alice" }, { $set: { age: 31 } }
    )
    db.users.updateMany(
      { status: "inactive" }, { $set: { archived: true } }
    )
  • upsert / findOneAndUpdate

    // Upsert(なければ挿入)
    db.users.updateOne(
      { email: "new@example.com" },
      { $set: { name: "New User" } },
      { upsert: true }
    )
    // findOneAndUpdate(更新後の値を返す)
    db.users.findOneAndUpdate(
      { name: "Alice" }, { $inc: { age: 1 } },
      { returnDocument: "after" }
    )
  • replaceOne / delete

    db.users.replaceOne(
      { name: "Alice" },
      { name: "Alice", age: 32, role: "admin" }
    )
    db.users.deleteOne({ name: "Bob" })
    db.users.deleteMany({ status: "inactive" })

クエリ演算子

比較演算子と論理演算子の一覧です。

演算子説明
$eq

等しい — { age: { $eq: 30 } } ※ { age: 30 } と同等

$ne

等しくない — { status: { $ne: "deleted" } }

$gt / $gte

より大きい / 以上 — { age: { $gte: 20 } }

$lt / $lte

より小さい / 以下 — { age: { $lt: 40 } }

$in / $nin

いずれかに一致 / 不一致 — { status: { $in: ["active", "pending"] } }

$and

全条件を満たす(暗黙的ANDも可)

$or

いずれかを満たす — { $or: [{ a: 1 }, { b: 2 }] }

$not / $nor

条件を否定 / いずれも満たさない

要素 & 評価演算子

  • $exists / $type

    db.users.find({ email: { $exists: true } })
    db.users.find({ deletedAt: { $exists: false } })
    db.users.find({ age: { $type: "number" } })
  • $regex / $text / $expr

    db.users.find({ name: { $regex: /^A/, $options: "i" } })
    db.users.find({ email: { $regex: "example\.com$" } })
    
    // $text(テキストインデックス必要)
    db.posts.find({ $text: { $search: "mongodb tutorial" } })
    
    // $expr: 集約式をクエリで使用
    db.orders.find({
      $expr: { $gt: ["$total", "$budget"] }
    })

配列演算子

  • $all / $elemMatch / $size

    db.posts.find({ tags: { $all: ["mongodb", "nosql"] } })
    db.students.find({
      scores: { $elemMatch: { $gte: 80, $lt: 90 } }
    })
    db.posts.find({ tags: { $size: 3 } })
  • 配列フィールドに対するクエリ演算子です。

    db.posts.find({ tags: "mongodb" })          // 配列内の要素で直接検索
    db.orders.find({ "items.name": "Book" })    // ネスト検索
    db.users.find({ "scores.0": { $gte: 80 } }) // インデックス指定

更新演算子

フィールドの値を変更する演算子の一覧です。

演算子説明
$set

フィールドの値を設定 — { $set: { name: "Alice" } }

$unset

フィールドを削除 — { $unset: { tmp: "" } }

$rename

フィールド名を変更 — { $rename: { "old": "new" } }

$inc

数値を加算 — { $inc: { views: 1 } }

$mul

数値を乗算 — { $mul: { price: 1.1 } }

$min / $max

現在値より小さい/大きい場合のみ更新

$currentDate

現在日時を設定 — { $currentDate: { updatedAt: true } }

配列更新演算子

  • $push / $addToSet / $pull / $pop

    { $push: { tags: "new" } }       // 要素を追加
    { $addToSet: { tags: "unique" } } // 重複なしで追加
    { $pull: { tags: "old" } }        // 条件一致の要素を削除
    { $pop: { tags: 1 } }             // 先頭(-1) or 末尾(1) を削除
    { $pullAll: { tags: ["a", "b"] } }
  • $each / $sort / $slice

    { $push: { tags: { $each: ["a", "b", "c"] } } }
    
    // $each + $sort + $slice: ソート後に先頭N件のみ保持
    db.users.updateOne({ _id: 1 }, { $push: {
      scores: { $each: [90, 85], $sort: -1, $slice: 5 }
    }})

位置演算子 & arrayFilters

  • $ / $[]

    // $: 条件に一致した最初の要素を更新
    db.users.updateOne(
      { "scores.subject": "math" },
      { $set: { "scores.$.grade": "A" } }
    )
    // $[]: 全要素を更新
    db.users.updateMany({}, { $inc: { "scores.$[].value": 5 } })
  • $[identifier] + arrayFilters

    db.users.updateMany({},
      { $set: { "scores.$[elem].passed": true } },
      { arrayFilters: [{ "elem.value": { $gte: 60 } }] }
    )
    // ネストした配列の更新
    db.posts.updateOne({ _id: 1 },
      { $push: { "comments.$[c].replies": { text: "reply" } } },
      { arrayFilters: [{ "c.author": "Alice" }] }
    )

集約パイプライン

基本ステージ

  • $match / $group

    db.orders.aggregate([
      { $match: { status: "completed" } },
      { $group: {
          _id: "$customerId",
          totalAmount: { $sum: "$amount" },
          avgAmount: { $avg: "$amount" },
          count: { $sum: 1 },
          items: { $push: "$item" }
      }}
    ])
  • $sort / $skip / $limit / $project

    db.orders.aggregate([
      { $sort: { totalAmount: -1 } },
      { $skip: 10 },
      { $limit: 5 },
      { $project: {
          _id: 0, customer: "$_id", totalAmount: 1,
          avgAmount: { $round: ["$avgAmount", 2] }
      }}
    ])
  • $addFields

    { $addFields: {
        fullName: { $concat: ["$first", " ", "$last"] }
    }}

$lookup & $unwind

  • $lookup + $unwind

    // $lookup: コレクション結合(LEFT OUTER JOIN)
    db.orders.aggregate([
      { $lookup: {
          from: "users", localField: "userId",
          foreignField: "_id", as: "userInfo"
      }},
      { $unwind: "$userInfo" }
    ])
  • $unwind

    // タグのカウント
    db.posts.aggregate([
      { $unwind: "$tags" },
      { $group: { _id: "$tags", count: { $sum: 1 } } },
      { $sort: { count: -1 } }
    ])
    // 空配列のドキュメントも保持
    { $unwind: { path: "$tags", preserveNullAndEmptyArrays: true } }
  • $lookup + pipeline

    { $lookup: {
        from: "orders",
        let: { userId: "$_id" },
        pipeline: [
          { $match: { $expr: { $eq: ["$userId", "$$userId"] } } },
          { $sort: { createdAt: -1 } },
          { $limit: 3 }
        ],
        as: "recentOrders"
    }}

$facet & $bucket

  • $facet

    db.products.aggregate([{ $facet: {
      priceStats: [
        { $group: { _id: null, avg: { $avg: "$price" } } }
      ],
      categoryCount: [
        { $group: { _id: "$category", count: { $sum: 1 } } },
        { $sort: { count: -1 } }
      ],
      topProducts: [
        { $sort: { sales: -1 } }, { $limit: 5 }
      ]
    }}])
  • $bucket / $out / $merge

    { $bucket: {
        groupBy: "$age",
        boundaries: [0, 20, 40, 60, 80],
        default: "Other",
        output: { count: { $sum: 1 }, avgIncome: { $avg: "$income" } }
    }}
    { $out: "monthlySummary" }
    { $merge: {
        into: "summary", on: "_id",
        whenMatched: "replace", whenNotMatched: "insert"
    }}

インデックス

MongoDB がサポートするインデックス種類の一覧です。

種類用途
単一フィールド

1つのフィールドの等値・範囲検索

複合

複数フィールドの組み合わせ検索

マルチキー

配列フィールド(自動作成)

テキスト

全文検索($text クエリ)

TTL

一定時間後にドキュメントを自動削除

ユニーク

フィールド値の一意性を保証

部分

条件を満たすドキュメントのみインデックス

ワイルドカード

動的フィールドに対応(スキーマレス向け)

インデックス作成

  • 用途別のインデックス作成パターンです。

    db.users.createIndex({ email: 1 })        // 単一(昇順)
    db.users.createIndex({ createdAt: -1 })   // 単一(降順)
    db.orders.createIndex({ customerId: 1, orderDate: -1 }) // 複合
    db.users.createIndex({ email: 1 }, { unique: true })    // ユニーク
    // テキストインデックス
    db.posts.createIndex({ title: "text", content: "text" })
    // TTLインデックス(1時間後に自動削除)
    db.sessions.createIndex(
      { createdAt: 1 }, { expireAfterSeconds: 3600 }
    )
    // 部分インデックス
    db.orders.createIndex(
      { status: 1 }, { partialFilterExpression: { status: "active" } }
    )
    db.data.createIndex({ "$**": 1 }) // ワイルドカード

explain & 統計

  • explain

    db.users.find({ email: "test@example.com" })
      .explain("executionStats")
    // IXSCAN=インデックス使用, COLLSCAN=フルスキャン
    // totalDocsExamined, executionTimeMillis を確認
  • クエリの実行計画とパフォーマンス確認です。

    db.users.getIndexes()              // インデックス一覧
    db.users.dropIndex("email_1")     // 削除
    db.users.dropIndexes()             // 全削除(_id以外)
    db.users.hideIndex("email_1")     // 一時無効化
    db.users.unhideIndex("email_1")   // 再有効化
    db.users.stats().totalIndexSize    // サイズ確認
    db.users.stats({ scale: 1024 })   // ストレージ情報(KB)

データモデリング

埋め込み vs 参照

  • Embedding

    // 1:1 / 1:少数に適する(1回のクエリ、アトミック更新)
    db.users.insertOne({
      name: "Alice",
      address: { city: "Tokyo", zip: "100-0001" },
      orders: [
        { item: "Book", price: 1500 },
        { item: "Pen", price: 200 }
      ]
    })
  • Referencing

    // 1:多数 / 多:多に適する(データ重複なし)
    // users: { _id: ObjectId("user1"), name: "Alice" }
    // orders: { userId: ObjectId("user1"), item: "Book" }
    
    // $lookup で結合して取得
    db.users.aggregate([{ $lookup: {
      from: "orders", localField: "_id",
      foreignField: "userId", as: "orders"
    }}])

スキーマバリデーション

  • JSONスキーマによるドキュメントの検証ルールです。

    db.createCollection("users", { validator: {
      $jsonSchema: {
        bsonType: "object",
        required: ["name", "email", "age"],
        properties: {
          name: { bsonType: "string" },
          email: { bsonType: "string", pattern: "^.+@.+$" },
          age: { bsonType: "int", minimum: 0, maximum: 150 },
          status: { enum: ["active", "inactive", "banned"] }
        }
      }
    }})
    // 既存コレクションにバリデーション追加
    db.runCommand({
      collMod: "users",
      validator: { $jsonSchema: { /* ... */ } },
      validationLevel: "moderate",
      validationAction: "warn"
    })

トランザクション & 運用

トランザクション

  • 複数操作のアトミック実行です。

    const session = db.getMongo().startSession()
    session.startTransaction()
    try {
      db.accounts.updateOne(
        { _id: "A" }, { $inc: { balance: -100 } }, { session }
      )
      db.accounts.updateOne(
        { _id: "B" }, { $inc: { balance: 100 } }, { session }
      )
      session.commitTransaction()
    } catch (e) {
      session.abortTransaction()
    } finally { session.endSession() }

ユーザー管理

  • createUser

    db.createUser({
      user: "appUser",
      pwd: "securePassword",
      roles: [
        { role: "readWrite", db: "myApp" },
        { role: "read", db: "reporting" }
      ]
    })
    // ロール: read, readWrite, dbAdmin,
    //   userAdmin, clusterAdmin, root
  • ユーザーの作成と権限設定です。

    db.dropUser("appUser")
    db.changeUserPassword("appUser", "newPassword")
    db.grantRolesToUser("appUser", [
      { role: "dbAdmin", db: "myApp" }
    ])
    db.revokeRolesFromUser("appUser", [
      { role: "read", db: "reporting" }
    ])