【MongoDB】MongoDBとPostgreSQL(JSONB)、どちらを選ぶべきか比較検証

MongoDB

こんにちは、かつコーチです。

これでMongoDB編は10本目、最終回です。

「MongoDBを採用しようと思っていたけど、PostgreSQLのJSONB型でも同じことができるのでは」。

PostgreSQL編の最終回(20本目)でも同じテーマを扱いましたが、あちらはPostgreSQL側からの視点でした。

今回はMongoDB編の締めくくりとして、MongoDB側から見た「PostgreSQLのJSONBとの違い」を整理し、実際にどちらを選ぶべきかの判断軸をまとめます。

MongoDB 7.x系のmongoshを前提に進めます。

MongoDBが「ドキュメント指向」である理由

スキーマレスという設計思想

ここまでの9本で扱ってきた通り、MongoDBはスキーマレス(コレクション内のドキュメントがそれぞれ異なる構造を持てる)というのが最大の特徴です。

// 同じコレクションに異なる構造のドキュメントを混在させられる
db.products.insertMany([
  { name: "ノートPC", cpu: "Core i7", ram_gb: 16 },
  { name: "マウス", color: "black", wireless: true }
]);

これは「思いつきで自由に構造を変えていい」という意味ではなく、アプリケーション側の要求に合わせてドキュメント構造を柔軟に進化させられるという設計上の強みです。

PostgreSQLのJSONB型も柔軟な構造を持てますが、それはあくまで「テーブルの中の1つのカラム」の話であり、テーブル自体の構造(主キー・他のカラム)は固定されたままです。

この「ドキュメント全体が柔軟か、一部のカラムだけが柔軟か」という違いが、両者の最も本質的なアーキテクチャの差です。

集約パイプラインという独自の集計基盤

MongoDB編6本目で扱った集約パイプラインは、MongoDBが標準で持つ強力な集計エンジンです。

// カテゴリごとの平均単価を集計する
db.sales.aggregate([
  { $match: { saleDate: { $gte: ISODate("2026-01-01") } } },
  { $group: { _id: "$category", avgPrice: { $avg: "$price" } } }
]);

SQLのGROUP BYと役割は近いものの、複数ステージを自由に組み合わせて段階的にデータを加工できる点は、MongoDB独自の発想です。

PostgreSQLでもJSONBカラムの中身をGROUP BYで集計することは可能ですが、ドキュメント全体を前提に設計された集約パイプラインほど、ネストしたデータの加工には向いていません。

リレーションとトランザクションの実情

$lookupの限界を正直に認める

MongoDB編6本目でも触れましたが、$lookupはSQLのJOINに相当する機能を持つものの、複数のコレクションを何段も結合するような設計には向いていません

// $lookupによる結合(多段になるとパフォーマンスが劣化しやすい)
db.orders.aggregate([
  { $match: { status: "shipped" } },
  { $lookup: {
      from: "customers",
      localField: "customerId",
      foreignField: "_id",
      as: "customerInfo"
  }}
]);

これはMongoDBの欠点というより、「ドキュメント指向データベースはそもそもリレーションを多用しない設計を前提にしている」という思想の表れです。

注文・商品・在庫のように明確なリレーションを何段も持つデータを扱うなら、MongoDB編8本目で扱った「埋め込み」を活用してリレーションそのものを減らす設計にするか、素直にPostgreSQLのようなRDBMSを検討する方が理にかなっています。

トランザクションはMongoDBでも使える

MongoDBは4.0以降、複数ドキュメントにまたがるマルチドキュメントトランザクション(ACID特性を満たす一連の処理)に対応しています。

// レプリカセット環境でのトランザクション例
const session = db.getMongo().startSession();
session.startTransaction();
try {
  session.getDatabase("shop").accounts.updateOne(
    { _id: "account-A" }, { $inc: { balance: -1000 } }
  );
  session.getDatabase("shop").accounts.updateOne(
    { _id: "account-B" }, { $inc: { balance: 1000 } }
  );
  session.commitTransaction();
} catch (e) {
  session.abortTransaction();
  throw e;
}

PostgreSQLのトランザクションが「標準機能として最初から強力」なのに対し、MongoDBのトランザクションは「後から追加された機能であり、レプリカセット構成(MongoDB編9本目)が前提になる」という違いがあります。

金融処理のようにトランザクション整合性が業務要件の中心にあるなら、素直にRDBMSの実績を活かす方が安全というのが、複数案件を見てきた実感です。

どちらを選ぶべきかの判断軸

MongoDBが向いているケース

  • ドキュメント構造が要件によって大きく異なり、事前にスキーマを固定しにくい(CMSのコンテンツ、ログデータ、IoTのセンサーデータなど)
  • リレーションが少なく、1つのドキュメントで完結するデータが中心
  • 将来的な水平分散(シャーディング)を見据えた、大規模なドキュメントストアとしての運用を想定している

PostgreSQL(JSONB)が向いているケース

  • テーブル構造の大部分は固定で、一部の属性だけ柔軟にしたい
  • リレーションを多用し、JOINによるデータ取得が中心になる
  • 既存のRDBMS運用資産(バックアップ・監視・レプリケーション)を活かしたい

比較表:判断基準の整理

観点MongoDBPostgreSQL(JSONB)
スキーマ設計全体がスキーマレス固定カラム+部分的に柔軟
リレーション(結合)弱い($lookupは制約あり)得意(JOINがネイティブ)
トランザクション4.0以降で対応、レプリカセットが前提標準で強力(ACID完全対応)
集計処理集約パイプラインが柔軟で強力GROUP BYJSONB演算子
水平分散シャーディングを前提に設計されている拡張機能や別ミドルウェアが必要になりやすい
学習コスト独自クエリAPI・集約パイプラインの学習が必要SQLの知識で対応可能

この判断軸は、PostgreSQL編最終回で示したものと矛盾しないよう、同じ観点をMongoDB側の視点から見直したものです。

「新しい技術だから」ではなく、「自分たちのデータがリレーション中心かドキュメント中心か」で選ぶのが、両シリーズを通じての結論です。

まとめ

この記事のポイント

  • MongoDBはドキュメント全体がスキーマレス、PostgreSQLのJSONBはカラム単位の柔軟性という違いがある
  • $lookupによるリレーションの扱いはPostgreSQLのJOINに劣るため、リレーション中心の設計にはMongoDBは向かない
  • MongoDBのトランザクションは4.0以降の対応で、レプリカセット構成が前提になる
  • 「ドキュメント構造が要件で大きく異なるか」「リレーションを多用するか」を軸に選定するのが実践的

次に読むべき記事

  • MongoDBとは?ドキュメント指向NoSQLを初心者向けに解説(MongoDB編1本目)
  • スキーマ設計の考え方:埋め込みvs参照(MongoDB編8本目)
  • PostgreSQLとMongoDB、JSONBはどこまでMongoDBの代わりになるか比較検証(PostgreSQL編最終回)

これでMongoDB編(全10本)は完結です。

ここまでお読みいただき、ありがとうございました。

タグ: MongoDB, 中級者向け, 比較検証

タイトルとURLをコピーしました