MongoDB での配列サイズが 1 より大きいドキュメントのクエリ
- サンプルデータ
-
$size
演算子を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする -
$where
演算子を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする - MongoDB でドット表記を使用して配列サイズが 1 より大きいドキュメントをクエリする
-
$expr
(3.6+) を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする -
Aggregation
$facet
演算子を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする
配列のサイズを確認したり、サイズが特定の長さよりも大きいまたは小さい要素を見つける必要があるプロジェクトで作業する場合、$size
、$where
、$exists
などの MongoDB 演算子を使用できます。
以下で説明するアプローチは、配列の長さまたは配列サイズの問題を解決するのに役立ちます。
サンプルデータ
次のデータがあるとします。 このサンプル データを使用して、MongoDB で特定の配列サイズを持つドキュメントをクエリします。
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "reds"], book: { author:`xyz`, price:50, location:[`india`, `USA`, `nepal`]} },
{ item: "notebook", qty: 50, tags: ["reds", "blank"], book: { author:`xyz`, price:50, location:[`india`, `usa`]} },
{ item: "paper", qty: 100, tags: ["reds", "blank", "plain"], book: { author:`xyz`, price:50, location:[]}},
{ item: "planner", qty: 75, tags: ["blank", "reds"], book: { author:`xyz`, price:50, location:[`india`]} },
{ item: "postcard", qty: 45, tags: ["blue"], book:{} }
]);
$size
演算子を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする
MongoDB の配列演算子クラスは、配列を参照してドキュメントを取得するために使用される多くの演算子で構成されています。 $size
はその 1つです。 $size
演算子は、特定のサイズの配列フィールドを含むドキュメントを取得するために使用されます。
配列でのみ機能し、数値をパラメーターとして受け入れます。
$size
演算子の主な機能は次のとおりです。
- 配列フィールドをユーザーが指定したサイズと比較することから開始し、続行します。
- 前の手順を満たすフィールドを含むドキュメントを取得します。
構文:
{array-field: {$size: <length-of-array>}}
この場合、array-field
はドキュメント内の目的のフィールドの名前であり、length-of-array
は長さに一致する任意の数値です。
MongoDB で $size
演算子を使用する方法を確認するために、いくつかの例を以下で共有します。
tags
の長さが 1 の要素を検索
db.inventory.find({tags:{$size:1}})
出力:
books.location
の長さが 1 である要素を検索
db.inventory.find({books.location:{$size:1}}
出力:
$where
演算子を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする
JavaScript 式または完全な JavaScript 関数を含む文字列をクエリ システムに提供するには、$where
演算子を使用します。 これにより柔軟性が向上しますが、データベースがコレクション内のすべてのドキュメントに対して JavaScript 式または関数を実行する必要があります。
this
または obj
のいずれかを使用して、JavaScript 式または関数でレコードを参照します。
構文:
{ $where: <string|JavaScript Code> }
$where
演算子の動作を示す例を以下に示します。
tags
の長さが 1 の要素を検索
db.inventory.find({tags:{$where:`this.tags.length == 1`}}
出力:
tags
の長さが 1 以上の要素を検索
db.inventory.find({tags:{$where:`this.tags.length >= 1`}}
books.location
の長さが 1 である要素を検索
you cannot check this with the help of $where
$where
クエリ演算子は、最上位のドキュメントでのみ使用してください。 ネストされたページ内では動作しません。
MongoDB でドット表記を使用して配列サイズが 1 より大きいドキュメントをクエリする
埋め込みドキュメントの配列要素とフィールドにアクセスするために、MongoDB はドット表記を採用しています。
配列要素へのアクセス
ゼロから始まるインデックス位置で配列要素を指定またはアクセスするには、配列名をドット (.
) とゼロから始まるインデックス位置で連結し、引用符で囲みます。
構文:
"<array>.<index>"
たとえば、ドキュメント内の次のフィールドについて考えてみましょう。
{
...
contribs: [ "Turing machine", "Turing test", "Turingery" ],
...
}
contribs.2
配列の 3 番目のメンバーを識別するには、ドット表記 "contribs.2"
を使用します。
tags
の長さが 0 より大きい要素を検索
db.inventory.find({tags.0:{$exists:true`}}
It will look for elements with at least one tag // array with a zero-based index.
books.location
の長さが 1 より大きい要素を検索
db.invantory.find({book.location.1: {$exists:true}}
// It looks for all components in whose book. There are at least two elements to a place.
$expr
(3.6+) を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする
構文:
{ $expr: { <expression> } }
$tags
の長さが 0 より大きいドキュメントを検索
db.invantory.find({
$expr: {
$gt: [{ $size: { $ifNull: ["$tags", []] } }, 0]
}
})
$books.location
の長さが 1 より大きい要素を検索
db.invantory.find({
$expr: {
$gt: [{ $size: { $ifNull: ["$book.location", []] } }, 1]
}
})
// $ifNull: ["$book.location", []] this is used to avoid any error if book.location is null
Aggregation $facet
演算子を使用して、MongoDB で配列サイズが 1 より大きいドキュメントをクエリする
このオペレーターは、1つのステージで同じ入力ドキュメントのセットに対する多数の集約を処理します。 各パイプラインには、結果がドキュメントの配列として保存される出力ドキュメント内のフィールドがあります。
$facet
ステージでは、1つの集計ステージ内で複数のディメンションまたはファセットにわたってデータを特徴付ける多面的な集計を作成できます。 多面的な集計は、データの参照と分析を支援する複数のフィルターと分類を提供します。
たとえば、小売業者はファセットを使用して、製品の価格、メーカー、サイズなどに基づいてフィルターを作成し、検索結果を絞り込むことがよくあります。
入力ドキュメントは $facet
ステップに 1 回だけ送信されます。 $facet
を使用すると、複数回取得する必要なく、入力ドキュメントの同じセットで多数の集計を行うことができます。
構文:
{ $facet:
{
<outputField1>: [ <stage1>, <stage2>, ... ],
<outputField2>: [ <stage1>, <stage2>, ... ],
...
}
}
各パイプラインの出力フィールドの名前を入力します。
$facet
の各サブパイプラインは、入力ドキュメントの同一のセットを受け取ります。 これらのサブパイプラインは互いに独立しており、それぞれによって生成されたドキュメント配列は、出力ドキュメントの異なるフィールドに格納されます。
同じ $facet
ステージ内で、1つのサブパイプラインの出力を別のサブパイプラインの入力として利用することはできません。 $facet
の後に追加のステージを追加し、さらに集計が必要な場合は、目的のサブパイプライン出力のフィールド名 outputField>
を示します。
$facet
ステージでのインデックスの使用
そのサブパイプラインが $match
を使用する場合、または $facet
がパイプラインの最初のステップである場合でも、$facet
ステージとそのサブパイプラインはインデックスを使用できません。 実行中、$facet
ステージは常に COLLSCAN
を実行します。
次の artwork
コレクションに在庫が保管されているオンライン ストアを考えてみましょう。
{ "_id" : 1, "title" : "The Pillars of Society", "artists" : "Grosz", "year" : 1926,
"price" : NumberDecimal("199.99"),
"tags" : [ "painting", "satire", "Expressionism", "caricature" ] }
{ "_id" : 2, "title" : "Melancholy III", "artists" : "Munch", "year" : 1902,
"price" : NumberDecimal("280.00"),
"tags" : [ "woodcut", "Expressionism" ] }
{ "_id" : 3, "title" : "Dancer", "artists" : "Miro", "year" : 1925,
"price" : NumberDecimal("76.04"),
"tags" : [ "oil", "Surrealism", "painting" ] }
{ "_id" : 4, "title" : "The Great Wave off Kanagawa", "artists" : "Hokusai",
"price" : NumberDecimal("167.30"),
"tags" : [ "woodblock", "ukiyo-e" ] }
{ "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,
"price" : NumberDecimal("483.00"),
"tags" : [ "Surrealism", "painting", "oil" ] }
{ "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,
"price" : NumberDecimal("385.00"),
"tags" : [ "oil", "painting", "abstract" ] }
{ "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893,
"tags" : [ "Expressionism", "painting", "oil" ] }
{ "_id" : 8, "title" : "Blue Flower", "artist" : "O`Keefe", "year" : 1918,
"price" : NumberDecimal("118.42"),
"tags" : [ "abstract", "painting" ] }
次の手順では、MongoDB のファセット機能を利用して、タグ、価格、および生成された年ごとに整理されたストアの在庫を消費者に表示します。 この $facet
ステージは、$sortByCount
、$bucket
、または $bucketAuto.
を使用してこの多面的な集約を実行する 3つのサブパイプラインで構成されています。
artwork
からの入力ドキュメントは、操作の開始時に一度だけデータベースから取得されます。
例:
db.artwork.aggregate( [
{
$facet: {
"categorizedByTags": [
{ $unwind: "$tags" },
{ $sortByCount: "$tags" }
],
"categorizedByPrice": [
// Filter out documents without a price e.g., _id: 7
{ $match: { price: { $exists: 1 } } },
{
$bucket: {
groupBy: "$price",
boundaries: [ 0, 150, 200, 300, 400 ],
default: "Other",
output: {
"count": { $sum: 1 },
"titles": { $push: "$title" }
}
}
}
],
"categorizedByYears(Auto)": [
{
$bucketAuto: {
groupBy: "$year",
buckets: 4
}
}
]
}
}
])
出力: