開発2026-02-06· 7 min

MongoよりPostgres: ほぼ常にそうする理由。

JSONB、配列、全文検索、生成カラム。Postgresは実質「関係代数付きMongo」です。使い分けの基準。

私たちは同じ光景を何度も見てきました。チームがプロジェクトを始め、誰かが「データの形がまだ分からないからMongoで始めよう」と言い、18ヶ月後にはマイグレーションを手書きし、アプリケーションコードで型を検証し、三つの異なるサービスが同じ顧客を三つの異なる形で保存していることに気づきます。「スキーマレス」という主張は、ほぼ常に本当の利点ではありません。それは高い利息のついた繰り延べ債務です。データの形は常に存在します。選べるのはそれがエンジンの中に住むか、最後にエンドポイントを書いた人の頭の中に住むかだけです。

私たちの立場はシンプルです。非常に具体的な理由がない限り、Postgresから始めます。そしてその具体的な理由はめったに現れません。

PostgresはJSONBを10年以上前から備えており、その演算子はMongoで行うほぼすべてをカバーします。-> 演算子はフィールドをJSONとして取り出し、->> はテキストとして取り出し、@> はあるドキュメントが別のドキュメントを含むかを問い、jsonb_path_exists は完全なJSONPath式を評価します。私たちの典型的なテーブルは、型付きのカラムと metadata jsonb カラムを混在させます。id、email、created_at は制約付きの実カラムとして存在し、本当に可変なもの、つまりテナント別フラグ、UI設定、変わった設定はGINインデックスを上に乗せたJSONBに入れます。参照整合性を犠牲にせず両方の世界の良いところを得られます。

ネイティブ配列も過小評価されている機能です。エンティティが短く範囲の決まったタグ、ロール、関連IDのリストを持ち、それらを行と一緒にほぼ常に読む場合、unnest と ANY を伴う text[] や uuid[] は結合テーブルより性能が良く、モデルもより読みやすくなります。もちろん常にではありません。関係そのものに属性が必要なら結合テーブルに戻ります。しかし「すべてのN:M関係は新しいテーブル」というルールは教義であって工学ではありません。

全文検索はPostgresが本当に差を広げる領域です。言語別辞書を持つ tsvector と、トライグラム類似度のための pg_trgm を組み合わせると、スペイン語、カタルーニャ語、フランス語、ドイツ語、イタリア語の検索を、ステミングと打ち間違いへの耐性とともに処理できます。Mongoのテキストインデックスでは届かない領域です。アクセントや特殊文字、ドイツ語の複合語を扱うヨーロッパ向けでは、これは細部ではなく、使える検索と顧客が諦める検索の違いです。

その上にgenerated columnsを重ねます。search tsvector GENERATED ALWAYS AS (to_tsvector('japanese', coalesce(title,'') || ' ' || coalesce(body,''))) STORED というカラムにGINインデックスを張れば、トリガーもアプリケーションロジックも不要で、ソースフィールドとインデックスがズレる余地のない即時検索が手に入ります。

マルチドキュメントトランザクションはMongoにも数年前から存在しますが、依然として扱いにくいです。レプリカセットを要求し、より厳しい時間制限を持ち、APIも快適ではありません。Postgresではトランザクションはトランザクションであり、触れるすべてに及びます。ドメインがエンティティをまたぐ不変条件を持つとき、そして現実のドメインのほぼすべてが持つとき、これは効いてきます。

運用面の現実が決め手になります。WALによるポイントインタイムリカバリ、ダウンタイムなしでバージョン間を移動するための論理レプリケーション、成熟した拡張、そして何年も磨かれてきたPrisma、Drizzle、SQLAlchemyのようなORM。Mongoのエコシステムも良いですが、Postgresのものはより深く、より古いです。

MONGOが本当に勝つとき。Mongoに居場所がないと言っているわけではありません。具体的なシナリオではうまく機能します。各ドキュメントが本当に異なる、深く可変な形を持つドキュメント、たとえばCMSの下書き履歴で各バージョンが独自の構造を持つ場合。自動TTLを伴う書き込みの多い時系列ワークロードで、複雑なクエリより挿入のシンプルさが重要な場合。あるいは組織の残りがすでにMongoで動いており、運用の一貫性が最適な技術選択を上回る場合です。

スキーマは官僚主義ではありません。存在する中で最も安価なドキュメントの形式です。型と制約を持つすべてのカラムは、誰も読まないwikiに書かなくて済む一文です。スキーマなしで始めても作業は節約されません。チームが二倍になり、なぜそのフィールドが時には文字列で時には配列なのか誰も覚えていないときに、利息付きで請求が来るだけです。