MongoDBチートシート - mongosh・CRUD・集計・インデックス

9分 で読める | 2026.04.10

公式ドキュメント

最頻出10項目

やりたいことコマンド
接続mongosh
DBを選択use school
コレクション一覧show collections
1件検索db.users.findOne({ _id: id })
複数検索db.users.find({ active: true })
1件追加db.users.insertOne({ name: "Ada" })
一部を更新db.users.updateOne(filter, { $set: update })
1件削除db.users.deleteOne(filter)
インデックス作成db.users.createIndex({ email: 1 })
集計db.orders.aggregate(pipeline)

更新・削除の前には、同じ条件で find()countDocuments() を実行し、対象を確認します。初めは updateOne()deleteOne() を優先してください。

接続と確認

mongosh
mongosh "mongodb://localhost:27017/school"

Atlasなどへ接続するときは、ユーザー名やパスワードをコマンドへ直書きしないでください。接続文字列がシェル履歴やプロセス一覧へ残る可能性があります。環境変数や秘密情報管理サービスを使い、認証情報をリポジトリへ保存しません。

show dbs
use school
db
show collections
db.version()

use school だけではDBは作成されません。最初のデータが保存された時点で作成されます。

検索

db.users.findOne({ email: "student@example.com" });

db.users.find(
  { active: true, age: { $gte: 18 } },
  { name: 1, email: 1, _id: 0 },
);

db.users
  .find({ role: { $in: ["student", "mentor"] } })
  .sort({ createdAt: -1 })
  .limit(20);
演算子意味
$eq / $ne等しい / 等しくない
$gt / $gteより大きい / 以上
$lt / $lteより小さい / 以下
$in / $nin一覧に含まれる / 含まれない
$or / $andいずれか / すべて
$existsフィールドが存在するか
$elemMatch配列要素が複数条件を満たすか

ユーザー入力から正規表現を作る場合は、特殊文字と計算量に注意してください。先頭一致できる検索や専用の検索機能を検討します。

ドキュメントと配列を検索する

db.students.find({ "profile.city": "Tokyo" });
db.students.find({ tags: "javascript" });
db.students.find({
  scores: { $elemMatch: { subject: "math", value: { $gte: 80 } } },
});

ドット記法で入れ子のフィールドを指定できます。配列に単一の値を指定すると、その要素を含むドキュメントに一致します。同じ配列要素が複数条件を満たす必要がある場合は $elemMatch を使います。

存在しないフィールドと null は検索条件によって同時に一致することがあります。区別したい場合は $exists と型の条件を組み合わせてください。

射影・並べ替え・ページング

db.users.find(
  { active: true },
  { name: 1, email: 1 },
);

db.users
  .find({ active: true })
  .sort({ createdAt: -1, _id: -1 })
  .limit(20);

射影は必要なフィールドだけを返し、通信量や不用意なデータ露出を減らします。通常は包含指定と除外指定を混在できませんが、_id: 0 は包含指定と併用できます。

大きなページ番号での skip() は読み飛ばすコストが増えます。大量データでは、並べ替えキーと前回の最後の値を使う方式を検討します。

挿入

db.users.insertOne({
  name: "Ada",
  email: "student@example.com",
  active: true,
  createdAt: new Date(),
});

db.users.insertMany([
  { name: "Aki", active: true },
  { name: "Sora", active: false },
]);

insertMany() は途中で失敗した場合の扱いがオプションで変わります。大量投入では、重複や再実行時の結果を事前に決めてください。

更新

const filter = { email: "student@example.com" };

db.users.find(filter);
db.users.countDocuments(filter);

db.users.updateOne(filter, {
  $set: { active: true },
  $inc: { loginCount: 1 },
});
演算子用途
$set指定フィールドを設定
$unset指定フィールドを削除
$inc数値を加算
$push配列へ追加
$addToSet重複を避けて配列へ追加
$pull条件に一致する配列要素を削除
db.users.updateOne(
  { email: "student@example.com" },
  { $set: { name: "Ada" } },
  { upsert: true },
);

upsert: true は一致するデータがなければ挿入します。検索条件が不十分だと意図しない新規データが作られるため、一意インデックスと合わせて使います。

replaceOne() はドキュメント全体を置換します。フィールドの消失を避けたい通常の更新では $set を使います。

更新結果の matchedCountmodifiedCount も確認します。

const result = db.users.updateOne(
  { _id: userId, active: false },
  { $set: { active: true, updatedAt: new Date() } },
);

printjson({
  matched: result.matchedCount,
  modified: result.modifiedCount,
});

matchedCount が0なら条件に一致していません。modifiedCount が0でも、保存済みの値と同じ値を設定しただけの場合があります。

削除

const filter = { _id: ObjectId("507f1f77bcf86cd799439011") };

db.users.find(filter);
db.users.countDocuments(filter);
db.users.deleteOne(filter);

deleteMany({}) は全件を削除します。drop() はコレクション、dropDatabase() は現在のDBを削除するため、バックアップ・接続先・対象件数を確認せず実行しないでください。本番操作では権限を最小化し、復元手順を用意します。

件数と重複しない値

db.users.countDocuments({ active: true });
db.users.estimatedDocumentCount();
db.users.distinct("role");

条件付きの正確な件数には countDocuments()、コレクション全体のおおよその件数を素早く知る用途には estimatedDocumentCount() を使います。

集計パイプライン

db.orders.aggregate([
  { $match: { status: "paid" } },
  {
    $group: {
      _id: "$userId",
      total: { $sum: "$amount" },
      count: { $sum: 1 },
    },
  },
  { $sort: { total: -1 } },
  { $limit: 10 },
]);
ステージ用途
$match条件で絞る
$project出力するフィールドを選ぶ・計算する
$groupグループごとに集計
$sort並べ替える
$limit件数を制限
$unwind配列を1要素ずつ展開
$lookup別コレクションと結合

なるべく早い段階で $match して処理量を減らします。$out$merge は結果をコレクションへ書き込むため、参照だけの集計と同じ感覚で実行しないでください。

必要なフィールドだけを返す例です。

db.orders.aggregate([
  { $match: { status: "paid" } },
  {
    $project: {
      _id: 0,
      orderId: "$_id",
      amount: 1,
      taxIncluded: { $multiply: ["$amount", 1.1] },
    },
  },
  { $limit: 20 },
]);

配列を展開して集計するときは $unwind を使います。

db.orders.aggregate([
  { $unwind: "$items" },
  {
    $group: {
      _id: "$items.productId",
      quantity: { $sum: "$items.quantity" },
    },
  },
]);

空配列や対象フィールドがないドキュメントを残す必要がある場合は、$unwindpreserveNullAndEmptyArrays を確認します。

インデックス

db.users.createIndex({ email: 1 }, { unique: true });
db.orders.createIndex({ userId: 1, createdAt: -1 });
db.users.getIndexes();

検索の実行計画を確認します。

db.orders
  .find({ userId: userId })
  .sort({ createdAt: -1 })
  .explain("executionStats");

executionStatstotalDocsExaminedtotalKeysExaminednReturned などを比較します。インデックスは検索を速くする一方、書き込みコストと保存容量を増やします。

db.users.dropIndex("email_1");

インデックス削除は本番性能や一意性に影響します。名前と利用状況を確認し、負荷の低い時間帯や運用手順に従って実行してください。

複合インデックスはフィールドの順序が重要です。実際の絞り込みと並べ替えに合わせ、実行計画で確認します。

db.orders.createIndex({ status: 1, createdAt: -1 });
db.orders.getIndexes();

一意インデックスを既存データへ追加する場合、重複データがあると作成に失敗します。先に重複を調査し、修正方針を決めてください。

コレクションの基本操作

db.createCollection("users");
db.users.countDocuments({});
db.users.estimatedDocumentCount();

明示的な作成は、バリデーションなどのオプションを先に設定したい場合に使います。通常は最初の書き込み時にもコレクションが作られます。

db.createCollection("profiles", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["userId", "name"],
      properties: {
        userId: { bsonType: "objectId" },
        name: { bsonType: "string" },
      },
    },
  },
});

スキーマ検証はアプリ側の検証を置き換えるものではありません。DB側とアプリ側の両方で、役割に応じた検証を行います。

安全確認の順番

更新・削除・書き込みを伴う集計は、次の順番で確認します。

  1. db と接続先を確認する
  2. 同じフィルタを find() で確認する
  3. countDocuments() で対象件数を確認する
  4. 可能ならステージング環境やバックアップで試す
  5. まず1件で実行し、結果を再検索する
  6. 必要な場合だけ複数件へ広げる

アプリケーションから操作する場合は、入力値を検証し、DBユーザーの権限を必要最小限にします。

参考リソース

← 一覧に戻る
PR
PR
PR
PR