MongoDB

2026.04.10

公式ドキュメント

概要

MongoDB は BSON 形式でドキュメントを格納する代表的なドキュメント指向データベースです。本チートシートでは mongosh (MongoDB Shell) から実行するコマンドを中心に、実務で頻出する CRUD・クエリ・集計・インデックス操作を整理します。コマンドは MongoDB 7.x / 8.x の公式マニュアルに基づいています。

最初に覚える最小セット

操作コマンド
接続mongosh
DB 選択use mydb
一覧確認show collections
件数確認db.users.countDocuments({})
検索db.users.find({ active: true })
1件挿入db.users.insertOne({ name: "Taro" })
部分更新db.users.updateOne(filter, { $set: update })
実行計画db.users.find(query).explain("executionStats")

削除・置換・集計結果の書き込みは、先に findcountDocuments で対象件数を確認してから実行しますdropDatabase()drop()deleteMany({})replaceOne()$out$merge は特に影響範囲を確認します。

接続と基本

コマンド説明
mongoshローカルの MongoDB に接続
mongosh "mongodb://host:27017"任意ホストに接続
mongosh "mongodb+srv://user:pass@cluster/db"Atlas SRV 接続
show dbsデータベース一覧
use mydbデータベースを選択(存在しなければ作成予約)
db現在のデータベース名
show collectionsコレクション一覧
db.stats()DB 統計
db.version()バージョン確認

データベース・コレクション管理

コマンド説明
db.createCollection("users")コレクション作成
db.users.drop()コレクション削除
db.dropDatabase()現在の DB を削除
db.users.renameCollection("members")リネーム
db.users.countDocuments({})件数(正確)
db.users.estimatedDocumentCount()メタ情報からの概算件数

CRUD 操作

挿入

コマンド説明
db.users.insertOne({name: "Taro"})1 件挿入
db.users.insertMany([{...}, {...}])複数挿入
db.users.insertMany(docs, {ordered: false})失敗時も継続

ポイント: insertManyで{ordered: false}を指定すると、途中でエラーが発生しても残りのドキュメントの挿入を継続します。大量データ投入時に便利です。

検索

コマンド説明
db.users.find()全件取得
db.users.find({age: {$gte: 18}})条件付き取得
db.users.findOne({_id: id})1 件取得
db.users.find({}, {name: 1, _id: 0})射影(projection)
db.users.find().sort({age: -1})降順ソート
db.users.find().limit(10).skip(20)ページング
db.users.distinct("country")値の一覧

更新

コマンド説明
db.users.updateOne({_id}, {$set: {age: 30}})1 件更新
db.users.updateMany({active: true}, {$inc: {points: 1}})複数更新
db.users.replaceOne({_id}, newDoc)置換
db.users.updateOne(filter, update, {upsert: true})無ければ挿入
db.users.findOneAndUpdate(filter, update, {returnDocument: "after"})更新後ドキュメントを返却

削除

コマンド説明
db.users.deleteOne({_id})1 件削除
db.users.deleteMany({active: false})複数削除
db.users.findOneAndDelete(filter)削除したドキュメントを返却

実践メモ: findOneAndUpdateに{returnDocument: "after"}を付けると、更新後のドキュメントが返されます。アトミックな更新+取得に最適です。

クエリ演算子

比較

演算子説明
$eq等しい
$ne等しくない
$gt / $gteより大きい / 以上
$lt / $lteより小さい / 以下
$inいずれかに一致
$ninいずれにも一致しない

論理

演算子説明
$andすべて満たす
$orいずれかを満たす
$norどれも満たさない
$not否定

要素

演算子説明
$existsフィールドの有無
$typeBSON 型で絞り込み

配列

演算子説明
$all指定値をすべて含む
$elemMatch要素ごとの複合条件
$size配列長で絞り込み

注意: $setとreplaceOneは異なります。$setは指定フィールドのみ更新、replaceOneはドキュメント全体を置換します。意図しないフィールド消失に注意しましょう。

更新演算子

演算子説明
$setフィールドを設定
$unsetフィールドを削除
$inc数値を加算
$mul数値を乗算
$min / $max最小/最大で更新
$renameフィールドをリネーム
$push配列に追加
$addToSet重複しないよう追加
$pull条件に合う要素を削除
$pop末尾/先頭を削除
$currentDate現在日時を設定

実用スニペット集

1. 部分一致(正規表現)

db.users.find({ name: /^Taro/i });

2. 複合条件

db.orders.find({
 status: "paid",
 total: { $gte: 1000 },
 createdAt: { $gte: new Date("2026-01-01") }
});

3. OR 条件

db.users.find({
 $or: [{ role: "admin" }, { plan: "premium" }]
});

4. 配列要素の複合条件

db.products.find({
 tags: { $elemMatch: { $in: ["sale", "new"] } }
});

5. Upsert

db.counters.updateOne(
 { _id: "visits" },
 { $inc: { value: 1 } },
 { upsert: true }
);

6. 集計:グループ集計

db.orders.aggregate([
 { $match: { status: "paid" } },
 { $group: { _id: "$userId", total: { $sum: "$amount" }, count: { $sum: 1 } } },
 { $sort: { total: -1 } },
 { $limit: 10 }
]);

7. 集計:JOIN($lookup)

db.orders.aggregate([
 {
 $lookup: {
 from: "users",
 localField: "userId",
 foreignField: "_id",
 as: "user"
 }
 },
 { $unwind: "$user" }
]);

8. 集計:フィールド追加

db.users.aggregate([
 {
 $addFields: {
 fullName: { $concat: ["$firstName", " ", "$lastName"] }
 }
 }
]);

9. 集計:日別集計

db.events.aggregate([
 {
 $group: {
 _id: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } },
 count: { $sum: 1 }
 }
 },
 { $sort: { _id: 1 } }
]);

10. インデックス作成

db.users.createIndex({ email: 1 }, { unique: true });
db.orders.createIndex({ userId: 1, createdAt: -1 });
db.posts.createIndex({ title: "text", body: "text" });

11. テキスト検索

db.posts.find({ $text: { $search: "mongodb index" } });

12. インデックス一覧・削除

db.users.getIndexes();
db.users.dropIndex("email_1");

13. 実行計画の確認

db.users.find({ email: "a@b.co" }).explain("executionStats");

14. Bulk Write

db.users.bulkWrite([
 { insertOne: { document: { name: "A" } } },
 { updateOne: { filter: { name: "A" }, update: { $set: { active: true } } } },
 { deleteOne: { filter: { name: "old" } } }
]);

15. トランザクション(レプリカセット必須)

const session = db.getMongo().startSession();
session.startTransaction();
try {
 session.getDatabase("shop").orders.insertOne({...}, { session });
 session.getDatabase("shop").stock.updateOne({...}, { $inc: { qty: -1 } }, { session });
 session.commitTransaction();
} catch (e) {
 session.abortTransaction();
 throw e;
} finally {
 session.endSession();
}

16. エクスポート / インポート(シェル外)

コマンド説明
mongoexport --uri="mongodb://localhost/shop" --collection=users --out=users.jsonJSON エクスポート
mongoimport --uri="mongodb://localhost/shop" --collection=users --file=users.jsonJSON インポート
mongodump --uri="mongodb://localhost" --out=backup/バイナリダンプ
mongorestore --uri="mongodb://localhost" backup/バイナリリストア

ポイント: 集計パイプラインでは$matchをパイプラインの先頭に配置し、インデックスを効かせることが性能最適化の基本です

集計ステージ早見表

ステージ説明
$match条件で絞り込み
$projectフィールド整形
$groupグループ化・集計
$sortソート
$limit / $skip件数制御
$lookup結合
$unwind配列を展開
$addFieldsフィールド追加
$set$addFields のエイリアス
$unsetフィールド削除
$count件数を返す
$facet複数パイプラインを並列実行
$bucketバケット集計
$merge結果を別コレクションに書き込み
$out結果を完全置換で書き込み

集計演算子(式)早見表

演算子説明
$sum / $avg / $min / $max合計/平均/最小/最大
$first / $last先頭/末尾
$push / $addToSet配列化
$concat文字列連結
$toUpper / $toLower大文字/小文字
$dateToString日付を文字列化
$condif 式
$ifNullnull 時のデフォルト

注意: COLLSCAN(コレクションスキャン)がexplain()で表示されたら、インデックスが効いていない証拠。適切なインデックスを追加しましょう。

実践メモ: TTLインデックスを使えば、セッションやログなどの一時データを自動削除できますexpireAfterSecondsで有効期限を指定します。

トラブルシューティング

状況原因 / 対処
E11000 duplicate keyユニークインデックス違反。既存値を確認
クエリが遅いexplain("executionStats")COLLSCAN を確認し、インデックス追加
$lookup が遅いlocalField / foreignField にインデックスを張る
トランザクション不可スタンドアロンではなくレプリカセット/シャードが必要
_id を変更したい不可。新ドキュメント挿入 + 旧削除で対応
日付比較が効かない文字列ではなく ISODate / new Date() を使用

Tips

  • 本番ではユニーク制約や必須フィールドに必ずインデックスを張る。
  • find() は Cursor を返す。大量データは for (const doc of cursor) で反復。
  • $match はパイプラインの先頭に置き、インデックスを効かせる。
  • ObjectId は生成時刻を含むので、_id で時系列ソートが概ね可能。
  • スキーマ検証には $jsonSchema バリデータを使う。
  • Atlas を使う場合はネットワーク IP 許可リストの設定を忘れない。

代表的なドライバ(Node.js 例)

import { MongoClient, ObjectId } from "mongodb";

const client = new MongoClient(process.env.MONGO_URL);
await client.connect();
const db = client.db("shop");
const users = db.collection("users");

// 挿入
const r = await users.insertOne({ name: "Taro", createdAt: new Date() });

// 取得
const u = await users.findOne({ _id: new ObjectId(id) });

// 一覧
const list = await users
 .find({ active: true })
 .project({ name: 1 })
 .sort({ createdAt: -1 })
 .limit(20)
 .toArray();

// 更新
await users.updateOne({ _id: r.insertedId }, { $set: { active: true } });

// 削除
await users.deleteOne({ _id: r.insertedId });

await client.close();

代表的なドライバ(Python 例 / PyMongo)

from pymongo import MongoClient, ASCENDING
from bson import ObjectId

client = MongoClient("mongodb://localhost:27017")
db = client["shop"]

db.users.insert_one({"name": "Taro"})
doc = db.users.find_one({"_id": ObjectId(id_str)})
for u in db.users.find({"active": True}).sort("createdAt", -1).limit(10):
 print(u)

db.users.create_index([("email", ASCENDING)], unique=True)

ユーザ・ロール管理

コマンド説明
db.createUser({user, pwd, roles})ユーザ作成
db.updateUser(user, {roles})ロール更新
db.dropUser(user)ユーザ削除
db.grantRolesToUser(user, roles)ロール付与
db.revokeRolesFromUser(user, roles)ロール取消
db.getUsers()ユーザ一覧
db.auth(user, pwd)認証

代表的な組込ロール: read, readWrite, dbAdmin, userAdmin, clusterAdmin, root

バックアップとリストア

# 全体バックアップ
mongodump --uri="mongodb://localhost" --out=backup/$(date +%F)

# 特定 DB のみ
mongodump --uri="mongodb://localhost" --db=shop --out=backup/

# リストア(新しい DB 名に)
mongorestore --uri="mongodb://localhost" --nsFrom='shop.*' --nsTo='shop_restored.*' backup/

よくある設計パターン

パターン説明
埋め込み(Embedding)親ドキュメントに子を配列で持つ。1:1 や少数の 1:N に向く
参照(Referencing)子ドキュメントに親の _id を持つ。多対多や大きな子に向く
Bucket時系列を時間単位でまとめて 1 ドキュメントに
Computed集計結果をあらかじめフィールドに保持
Schema VersioningschemaVersion で段階的に移行

インデックスの種類

種類説明
単一フィールド{field: 1} の基本形
複合{a: 1, b: -1} 前方プレフィクスが効く
マルチキー配列フィールドに自動で作成される
テキスト{field: "text"}$text 検索で利用
2dsphereGeoJSON 地理空間検索
ハッシュシャーディング用
ワイルドカード{"$**": 1} 未知のキーに対応
TTL{createdAt: 1} + expireAfterSeconds で自動削除
部分partialFilterExpression で対象を絞る
一意{unique: true} で重複禁止

スキーマ検証($jsonSchema)

db.createCollection("users", {
 validator: {
 $jsonSchema: {
 bsonType: "object",
 required: ["email", "createdAt"],
 properties: {
 email: { bsonType: "string", pattern: "^.+@.+$" },
 age: { bsonType: "int", minimum: 0, maximum: 150 },
 createdAt: { bsonType: "date" }
 }
 }
 },
 validationLevel: "strict",
 validationAction: "error"
});

Change Streams(変更通知)

const cs = db.orders.watch([
 { $match: { operationType: { $in: ["insert", "update"] } } }
]);
while (!cs.isClosed()) {
 if (cs.hasNext()) printjson(cs.next());
}

まとめ

MongoDB では、CRUD の基本に加えて、インデックス、explain()、集計パイプラインの $match 位置を押さえると調査と改善が進めやすくなります。削除や置換は対象件数を確認し、必要ならバックアップを取ってから実行します。

dropDatabase()drop()deleteMany({})$out$merge は影響が大きい操作です。本番データでは権限、接続先、バックアップ、対象条件を必ず確認してください。

参考リソース

← 一覧に戻る
PR
PR
PR
PR