SQL LEFT JOINをNull保持付きのMongoDB $lookupに変換する
SQL LEFT JOINが結果にマッチしないドキュメントを保持するためにpreserveNullAndEmptyArraysを使用した$lookupと$unwindに変換される方法を学びます。
Migration
詳細な説明
LEFT JOINからpreserveNullAndEmptyArrays付き$lookupへ
SQLのLEFT JOINは左テーブルのすべての行と、右テーブルのマッチする行(マッチしない場合はNULL)を返します。MongoDBは$lookupとpreserveNullAndEmptyArrays: trueを設定した$unwindの組み合わせでこれを実現します。
SQLの例
SELECT users.name, orders.total
FROM users
LEFT JOIN orders ON users.id = orders.user_id
生成されるMongoDBクエリ
db.users.aggregate([
{
$lookup: {
from: "orders",
localField: "id",
foreignField: "user_id",
as: "orders"
}
},
{
$unwind: {
path: "$orders",
preserveNullAndEmptyArrays: true
}
},
{
$project: {
name: 1,
"orders.total": 1
}
}
])
preserveNullAndEmptyArrays
これがINNER JOINとの重要な違いです。このオプションをtrueに設定すると、$unwindに以下を指示します:
as配列が空のドキュメント(マッチが見つからない)を保持asフィールドがnullまたは欠落しているドキュメントを保持
このオプションなしでは、マッチしないドキュメントは削除され、INNER JOINのように動作します。
INNER JOIN vs LEFT JOINの比較
| 結合タイプ | $unwind設定 | マッチしないドキュメント |
|---|---|---|
| INNER JOIN | { $unwind: "$field" } |
削除される |
| LEFT JOIN | { $unwind: { path: "$field", preserveNullAndEmptyArrays: true } } |
保持される |
結合フィールドへのアクセス
LEFT JOIN変換後、マッチしないドキュメントでは結合フィールドがnullになります。アプリケーションコードでは、ネストされたプロパティにアクセスする前にnull値をチェックしてください:
// アプリケーションコードで
const total = doc.orders ? doc.orders.total : null;
代わりに非正規化を検討する場合
同じコレクションで頻繁にLEFT JOINを実行している場合、関連データを親ドキュメントに直接埋め込む方が効率的かもしれません。MongoDBのドキュメントモデルはこの種の非正規化のために設計されており、ストレージスペースとクエリパフォーマンスをトレードオフします。
ユースケース
ユーザーの最新の注文やプロフィール設定などのオプションの関連データを表示するユーザープロフィールページでは、関連データが存在しなくてもユーザーレコードが常に返されることを保証するためにLEFT JOINを一般的に使用します。この変換パターンはMongoDBでもその保証を維持します。