MongoDB 配列のクエリ

MongoDBBeginner
オンラインで実践に進む

はじめに

この実験では、MongoDB で配列を効果的にクエリする方法を学びます。配列は MongoDB の基本的なデータ構造であり、単一のドキュメントフィールド内に値のリストを格納できます。この実験では、単純な要素のマッチングから、特殊な演算子を使用したより複雑なクエリまで、配列データを扱うための基本的なテクニックを解説します。配列の内容、サイズ、要素の位置に基づいてドキュメントを見つける方法を学びます。これらは MongoDB を扱うすべての開発者にとって重要なスキルです。

開始と基本的な配列マッチング

最初のステップでは、MongoDB サーバーに接続し、データベースを作成して、サンプルデータを挿入します。その後、配列内の要素をマッチングしてドキュメントを検索する基本的なクエリを実行します。

まず、MongoDB Shell (mongosh) を開いてデータベースと対話します。このコマンドは、実行中の MongoDB インスタンスに接続します。

mongosh

シェルに入ると、test> プロンプトが表示されます。arraylab という新しいデータベースに切り替えましょう。use コマンドは、データベースが存在しない場合は作成し、現在のコンテキストをそれに切り替えます。

use arraylab

次に、products という新しいコレクションにドキュメントを挿入します。各ドキュメントは製品を表し、tagscolors という 2 つの配列フィールドを含みます。次のコマンドをコピーしてシェルに貼り付けてください。

db.products.insertMany([
  {
    name: "Laptop",
    tags: ["electronics", "computer", "work"],
    colors: ["silver", "black", "blue"]
  },
  {
    name: "Smartphone",
    tags: ["electronics", "mobile", "communication"],
    colors: ["red", "blue", "green"]
  },
  {
    name: "Headphones",
    tags: ["electronics", "audio", "music"],
    colors: ["black", "white"]
  }
]);

配列内に特定の要素を含むドキュメントを見つけるには、その値を直接クエリします。このクエリは、タグに "mobile" を持つすべての製品を検索します。

db.products.find({ tags: "mobile" });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Smartphone',
    tags: [ 'electronics', 'mobile', 'communication' ],
    colors: [ 'red', 'blue', 'green' ]
  }
]

配列が要素の正確なシーケンスと一致するドキュメントを見つけることもできます。このクエリは、tags 配列がその特定の順序で正確に ["electronics", "computer", "work"] である製品を検索します。

db.products.find({ tags: ["electronics", "computer", "work"] });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  }
]

次のステップのために mongosh シェルに留まることができます。いつでもシェルを終了するには、exit と入力して Enter キーを押してください。

配列クエリ演算子 $all および $in の使用

単純なマッチングも便利ですが、MongoDB はより複雑な配列クエリのための強力な演算子を提供しています。このステップでは、順序に関係なく複数の要素にマッチさせるための $all と、要素のリストのいずれかにマッチさせるための $in の使い方を学びます。

前のステップで使用した products コレクションを引き続き使用します。

$all 演算子は、配列フィールドが指定されたすべての要素を含むドキュメントを選択します。クエリ内の要素の順序は関係ありません。「blue」と「silver」の両方で利用可能な製品を見つけましょう。

db.products.find({ colors: { $all: ["blue", "silver"] } });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  }
]

$in 演算子は、配列フィールドが指定された値のいずれかを含むドキュメントを選択します。これは配列要素に対する「OR」条件のように機能します。「music」タグまたは「work」タグのいずれかを持つ製品を見つけましょう。

db.products.find({ tags: { $in: ["music", "work"] } });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  },
  {
    _id: ObjectId("..."),
    name: 'Headphones',
    tags: [ 'electronics', 'audio', 'music' ],
    colors: [ 'black', 'white' ]
  }
]

これらの演算子を使用すると、配列の内容に基づいてドキュメントを検索する際の柔軟性が大幅に向上します。

配列のサイズと位置によるクエリ

配列内の要素数や特定要素の位置が重要になる場合があります。このステップでは、$size 演算子を使用して配列サイズに基づいたクエリ、およびドット記法を使用して要素の位置に基づいたクエリの方法を説明します。

$size 演算子は、指定された数の要素を持つ配列を含むドキュメントにマッチします。カラーがちょうど 2 つ利用可能な製品を見つけましょう。

db.products.find({ colors: { $size: 2 } });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Headphones',
    tags: [ 'electronics', 'audio', 'music' ],
    colors: [ 'black', 'white' ]
  }
]

配列内の特定の位置(インデックス)にある要素をクエリするには、"fieldName.index" の形式でドット記法を使用します。配列のインデックスはゼロベースであるため、最初の要素はインデックス 0 にあることに注意してください。このクエリは、tags 配列の最初の要素が「electronics」であるすべての製品を検索します。

db.products.find({ "tags.0": "electronics" });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  },
  {
    _id: ObjectId("..."),
    name: 'Smartphone',
    tags: [ 'electronics', 'mobile', 'communication' ],
    colors: [ 'red', 'blue', 'green' ]
  },
  {
    _id: ObjectId("..."),
    name: 'Headphones',
    tags: [ 'electronics', 'audio', 'music' ],
    colors: [ 'black', 'white' ]
  }
]

次に、2 番目のカラー(インデックス 1)が「black」である製品を見つけましょう。

db.products.find({ "colors.1": "black" });

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  }
]

埋め込みドキュメントの配列に対するクエリ

MongoDB における一般的で強力なパターンは、他のドキュメントを含む配列を持つことです。これらは埋め込みドキュメントまたはネストされたドキュメントとして知られています。これらのクエリには、すべての条件が同じ配列要素に適用されることを保証するために、特別な演算子 $elemMatch が必要です。

まず、specs 配列を持つ新しい製品をいくつか追加しましょう。specs 配列の各要素は、ramstorage、および price フィールドを持つドキュメントです。

db.products.insertMany([
  {
    name: "Gaming Laptop",
    tags: ["electronics", "computer", "gaming"],
    specs: [
      { ram: 16, storage: 512, price: 1200 },
      { ram: 32, storage: 1024, price: 2000 }
    ]
  },
  {
    name: "Office Laptop",
    tags: ["electronics", "computer", "work"],
    specs: [
      { ram: 8, storage: 256, price: 600 },
      { ram: 16, storage: 512, price: 800 }
    ]
  }
]);

次に、RAM が 16GB 以上で、価格が 1000 ドル未満の構成を持つラップトップを見つけたいとします。単純なクエリは正しく見えるかもしれませんが、誤った結果につながる可能性があります。例えば、db.products.find({ "specs.ram": { $gte: 16 }, "specs.price": { $lt: 1000 } }) は、ある埋め込みドキュメントが十分な RAM を持ち、別の埋め込みドキュメントが十分低い価格を持つ場合にドキュメントにマッチします。

配列内の 単一の 埋め込みドキュメントがすべての条件を満たすことを保証するには、$elemMatch 演算子を使用する必要があります。

db.products.find({
  specs: {
    $elemMatch: { ram: { $gte: 16 }, price: { $lt: 1000 } }
  }
});

このクエリは、「Office Laptop」のみを正しく見つけます。なぜなら、この製品には { ram: 16, storage: 512, price: 800 } という spec 要素があり、両方の条件を同時に満たしているからです。

出力例:

[
  {
    _id: ObjectId("..."),
    name: 'Office Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    specs: [
      { ram: 8, storage: 256, price: 600 },
      { ram: 16, storage: 512, price: 800 }
    ]
  }
]

配列フィールドのプロジェクション

クエリから返されるドキュメント全体が必要ない場合が多くあります。プロジェクションを使用すると、含めるフィールドまたは除外するフィールドを指定できます。配列の場合、MongoDB は $slice のような特別なプロジェクション演算子を提供し、返される配列要素を制御します。

$slice プロジェクション演算子は、配列のサブセットを返します。正の数を指定すると最初の N 個の要素が返され、負の数を指定すると最後の N 個の要素が返されます。

すべての製品を取得し、各製品の name と最初の 2 つの tags のみを返してみましょう。find の最初の引数 {} は、すべてのドキュメントにマッチする空のクエリドキュメントです。2 番目の引数はプロジェクションドキュメントです。デフォルトの _id フィールドを除外するために _id: 0 を使用します。

db.products.find({}, { name: 1, tags: { $slice: 2 }, _id: 0 });

出力例:

[
  { "name": "Laptop", "tags": ["electronics", "computer"] },
  { "name": "Smartphone", "tags": ["electronics", "mobile"] },
  { "name": "Headphones", "tags": ["electronics", "audio"] },
  { "name": "Gaming Laptop", "tags": ["electronics", "computer"] },
  { "name": "Office Laptop", "tags": ["electronics", "computer"] }
]

もう 1 つ便利なプロジェクション演算子は、位置指定演算子 $ です。配列をクエリする場合、この演算子は、クエリ条件にマッチした最初の要素のみがプロジェクションされた配列フィールドで返されることを保証します。

「mobile」タグを持つ製品を見つけ、tags 配列から name とその特定のマッチするタグのみを返してみましょう。

db.products.find({ tags: "mobile" }, { name: 1, "tags.$": 1, _id: 0 });

出力例:

[{ "name": "Smartphone", "tags": ["mobile"] }]

これは、アプリケーションで完全な配列を処理することなく、大きな配列の関連部分のみを取得するのに非常に効率的です。

まとめ

この実験では、MongoDB における配列クエリの基本的なテクニックを学びました。基本的な要素マッチングから始め、$all$in$size のような強力な配列演算子の使用に進みました。また、要素の位置によるクエリ方法や、$elemMatch を使用して埋め込みドキュメントの配列を正しくクエリする方法も探求しました。最後に、$slice および位置指定 $ 演算子を使用して特定の配列要素をプロジェクションすることにより、クエリの出力を整形する方法を学びました。これらのスキルは、MongoDB の複雑なドキュメント構造からデータを効果的に管理および取得するために不可欠です。