Docs Menu
Docs Home
/
MongoDB Atlas
/ /

操作 を削減$lookup

項目一覧

  • Overview
  • 非正規化
  • 詳細

$lookup操作は、指定されたフィールドに基づいて同じデータベース内の 2 つのコレクションのデータを結合します。 $lookup操作は、データがリレーショナルデータベースと同様に構造化されており、大規模な階層データセットをモデル化する必要がある場合に役立ちます。 ただし、これらの操作では 1 つのコレクションではなく 2 つのコレクションに対してロジックを読み取って実行する必要があるため、時間がかかり、リソースが集中する可能性があります。

$lookup操作を頻繁に実行する場合は、アプリケーションが 1 つのコレクションをクエリして必要な情報をすべて取得できるようにスキーマを再構築することを検討してください。 埋め込みドキュメントと配列を含む MongoDB の柔軟なスキーマ モデルを利用して、単一のドキュメント構造でデータ間の関係をキャプチャできます。 この非正規化モデルを使用して、MongoDB の豊富なドキュメントを活用し、アプリケーションが 1 回のクエリで関連データを検索および操作できるようにします。

次の例は、 $lookup操作を削減するために設計された 2 つのスキーマ構造を示しています。

たとえば、食料品店が 1 対 1 の在庫と食料品情報を 2 つの個別のコレクションで追跡する次の例を考えてみましょう。 各在庫アイテムは、一意の機能停止アイテムに対応しています。 nutrition_idフィールドは、表形式データベースと同様に、 inventoryコレクションをnutrition_factsコレクションにリンクします。

// inventory collection
{
"name": "Pear",
"stock": 20,
"nutrition_id": 123, // reference to a nutrition_fact document
...
}
{
"name": "Candy Bar",
"stock": 26,
"nutrition_id": 456,
...
}
// nutrition_facts collection
{
"_id": 123,
"calories": 100,
"grams_sugar": 17,
"grams_protein": 1,
...
}
{
"_id": 456,
"calories": 250,
"grams_sugar": 27,
"grams_protein": 4,
...
}

アプリケーションが在庫商品のレシピをnameでリクエストする場合、このスキーマ構造では、在庫商品のnutrition_idと一致するエントリを見つけるために、 nutrition_factsコレクションの$lookupが必要です。

代わりに、 inventoryコレクションに機能情報を埋め込むことができます。

// inventory collection
{
"name": "Pear",
"stock": 20,
"nutrition_facts": {
"calories": 100,
"grams_sugar": 17,
"grams_protein": 1,
...
}
...
}
{
"name": "Candy Bar",
"stock": 26,
"nutrition_facts": {
"calories": 250,
"grams_sugar": 27,
"grams_protein": 4,
...
}
...
}

これにより、 inventoryの食材をクエリすると、別のクエリや$lookup操作を必要とせずに、資格情報が結果に含まれます。 コレクション間のデータに 1 対 1 の関係がある場合は、ドキュメントの埋め込みを検討してください。

表形式データベースと同様に、データベースのplayersコレクション内のドキュメントがteamsコレクション内のドキュメントを参照する次の例を考えてみます。

// players collection
{
"team_id": 1, // reference to a team document
"name": "Nick",
"position": "Pitcher"
...
}
{
"team_id": 1,
"name": "Anuj",
"position": "Shortstop"
...
}
// teams collection
{
"_id": 1,
"name": "Danbury Dolphins"
...
}

アプリケーションがチームのプレイヤーのリストをリクエストする場合、このスキーマ構造はteam_idに一致する各プレイヤーを検索するために、 playersコレクションの$lookupを必要とします。

代わりに、チーム ドキュメント自体に配列にplayersを一覧表示できます。

// teams collection
{
"_id": 1,
"name": "Danbury Dolphins",
"players": [
{
"name": "Nick",
"position": "Pitcher"
...
},
{
"name": "Anuj",
"position": "Shortstop"
...
}
]
}

配列 を使用して関連データを保持することで、アプリケーションは$lookup操作や他のコレクションのインデックスを必要とせずに、そのチームのプレイヤーを含む完全なteam情報を取得できます。 この場合、配列を使用する方が、情報を個別のコレクションに保存するよりもパフォーマンスが優れています。

注意

上記の例では、ベース チームには一定数のメンバーがあり、 の配列が大きくなりすぎるリスクはありません。

大規模な配列への読み取りと書き込みのパフォーマンス コストは、 $lookup操作を回避することで得られるメリットを超える可能性があります。 配列が無制限または大きすぎる場合、それらの配列は読み取りと書込みのパフォーマンスを低下させる可能性があります。

配列にインデックスを作成すると、配列内の各要素にインデックスが付けられます。 その配列に頻繁に書き込む場合、大きくなる可能性のある配列フィールドのインデックス作成や再インデックス作成のパフォーマンス コストが重大になる可能性があります。

Tip

以下も参照してください。

スキーマの非正規化とは、フィールドを重複させたり、既存のフィールドから新しいフィールドを生成したりするプロセスです。 非正規化により、次のようなさまざまなケースで読み取りパフォーマンスが向上します。

  • 定期クエリには、別のコレクション内の大きなドキュメントのいくつかのフィールドが必要です。 2 つの異なるコレクションをマージしたり、頻繁に$lookup操作を実行したりするように、定期クエリの対象となるコレクションの埋め込みドキュメントにこれらのフィールドのコピーを保持することを選択できます。

  • コレクション内の一部のフィールドの平均値は、頻繁に要求されます。 書込みの一部として更新され、そのフィールドの実行平均を維持する別の コレクションに派生フィールドを作成することを選択できます。

関連データをグループ化するには、重複のないドキュメントまたは配列の埋め込みが推奨されますが、個別のコレクションを維持する必要がある場合は非正規化によって読み取りパフォーマンスが向上します。

注意

スキーマを非正規化する場合、一貫性のある重複データを維持する必要があるのはユーザーの責任です。

スキーマに最適な構造は、アプリケーションのコンテキストによって異なります。 次のリソースでは、データ モデリングに関する詳細情報と、埋め込みドキュメントと配列のその他のユースケース例を提供しています。

柔軟なデータモデルをスキーマに組み込む方法については、MongoDB.live 2020 の以下のプレゼンテーションを参照してください。

MongoDB で配列をクエリする方法の詳細については、「 配列のクエリ 」を参照してください

配列が適切に機能する状況については、次の設計パターンを参照してください。

  • 属性パターンを使用して、各映画が国のサブセットで公開される映画データなど、属性の一意の組み合わせを持つデータを処理します。

  • 時間範囲データなど、厳密にグループ化されたデータまたは連続したデータを処理する場合は、バケット パターンを使用します。

  • 多形パターンを使用して、複数のスポーツにわたるプレイヤー レコードなど、同じコレクション内の異なる形状のドキュメントを処理します。

データを重複させることによってスキーマが改善される状況については、次の設計パターンを参照してください。

  • 拡張参照パターンを使用して、大きなドキュメントから頻繁に読み取られるデータの部分を小さなドキュメントに複製します。

戻る

スキーマの改善