これはMongoDBでの私の最初の日なので、私と一緒に簡単に行ってください:)
おそらく英語が私の母国語ではないため、$unwind
演算子を理解できません。
db.article.aggregate(
{ $project : {
author : 1 ,
title : 1 ,
tags : 1
}},
{ $unwind : "$tags" }
);
プロジェクトオペレーターは、私が理解できるものだと思います(SELECT
に似ていますよね?)。ただし、$unwind
(引用)は、すべてのソースドキュメント内の展開された配列のメンバーごとに1つのドキュメントを返します。
これはJOIN
のようなものですか?はいの場合、$project
の結果(_id
、author
、title
、およびtags
フィールドと)をtags
配列と比較する方法?
[〜#〜] note [〜#〜]:MongoDB Webサイトから例を取り上げましたが、tags
配列の構造はわかりません。タグ名の単純な配列だと思います。
まず、MongoDBへようこそ!
覚えておくべきことは、MongoDBがデータストレージに対して「NoSQL」アプローチを採用しているため、選択や結合などの考えがあなたの心から滅びることです。データを保存する方法は、ドキュメントとコレクションの形式であり、これにより、保存場所からデータを動的に追加および取得することができます。
つまり、$ unwindパラメーターの背後にある概念を理解するためには、まず、引用しようとしているユースケースが何を言っているのかを理解する必要があります。 mongodb.org のサンプルドキュメントは次のとおりです。
{
title : "this is my title" ,
author : "bob" ,
posted : new Date () ,
pageViews : 5 ,
tags : [ "fun" , "good" , "fun" ] ,
comments : [
{ author :"joe" , text : "this is cool" } ,
{ author :"sam" , text : "this is bad" }
],
other : { foo : 5 }
}
タグが実際には3つのアイテムの配列であることに注意してください。この場合、「楽しい」、「良い」、「楽しい」です。
$ unwindが行うことは、各要素のドキュメントを剥がし、その結果のドキュメントを返すことです。これを古典的なアプローチで考えると、「タグ配列内の各アイテムについて、そのアイテムのみを含むドキュメントを返す」と同等です。
したがって、次を実行した結果:
db.article.aggregate(
{ $project : {
author : 1 ,
title : 1 ,
tags : 1
}},
{ $unwind : "$tags" }
);
次のドキュメントが返されます。
{
"result" : [
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "fun"
},
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "good"
},
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "fun"
}
],
"OK" : 1
}
結果の配列で変更されるのは、タグの値で返されるものだけであることに注意してください。これがどのように機能するかについての追加の参照が必要な場合は、リンク here を含めました。これがお役に立てば幸いであり、これまでに出会った中で最高のNoSQLシステムの1つへの進出をお祈りします。
$unwind
は、配列要素ごとに1回、パイプライン内の各ドキュメントを複製します。
したがって、入力パイプラインにtags
に2つの要素を持つ1つの記事ドキュメントが含まれる場合、{$unwind: '$tags'}
は、tags
フィールドを除いて同じである2つの記事ドキュメントにパイプラインを変換します。最初のドキュメントでは、tags
には元のドキュメントの配列の最初の要素が含まれ、2番目のドキュメントでは、tags
に2番目の要素が含まれます。
例で理解しましょう
これは、companyドキュメントがどのように見えるかです:
$unwind
を使用すると、配列値フィールドを持つドキュメントを入力として取得し、配列内の各要素に1つの出力ドキュメントがあるように出力ドキュメントを生成できます。 ソース
それでは、会社の例に戻って、巻き戻しステージの使用を見てみましょう。このクエリ:
db.companies.aggregate([
{ $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
{ $project: {
_id: 0,
name: 1,
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
} }
])
量と年の両方の配列を持つドキュメントを作成します。
資金調達ラウンド配列内のすべての要素の調達額と資金調達年にアクセスしているためです。これを修正するには、プロジェクトステージの前にこの集約パイプラインにアンワインドステージを含め、資金調達ラウンド配列をunwind
したいということでこれをパラメーター化できます。
db.companies.aggregate([
{ $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
{ $unwind: "$funding_rounds" },
{ $project: {
_id: 0,
name: 1,
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
} }
])
funding_rounds
配列を見ると、funding_rounds
ごとにraised_amount
フィールドとfunded_year
フィールドがあることがわかります。したがって、unwind
は、funding_rounds
配列の要素であるドキュメントごとに出力ドキュメントを生成します。さて、この例では、値はstring
sです。ただし、配列内の要素の値のタイプに関係なく、unwind
はこれらの値のそれぞれに対して出力ドキュメントを生成し、問題のフィールドにはその要素のみが含まれるようにします。 funding_rounds
の場合、その要素は、project
ステージに渡されるすべてのドキュメントのfunding_rounds
の値として、これらのドキュメントの1つになります。これを実行した結果、amount
とyear
が得られます。コレクション内のすべての会社の各資金調達ラウンドに1つ。これが意味することは、私たちのマッチが多くの会社のドキュメントを作成し、それらの会社のドキュメントのそれぞれが多くのドキュメントをもたらすということです。すべての会社文書内の資金調達ラウンドごとに1つ。 unwind
は、match
ステージから渡されたドキュメントを使用してこの操作を実行します。そして、すべての会社のこれらのドキュメントはすべて、project
ステージに渡されます。
そのため、資金提供者がGreylock(クエリの例のように)であったすべてのドキュメントは、複数のドキュメントに分割され、一致するすべての会社の資金調達ラウンドの数に等しくなります$match: {"funding_rounds.investments.financial_org.permalink": "greylock" }
をフィルターします。そして、それらの結果のドキュメントはそれぞれ、project
に渡されます。現在、unwind
は、入力として受信するすべてのドキュメントの正確なコピーを作成します。すべてのフィールドには同じキーと値がありますが、例外が1つあります。つまり、funding_rounds
ドキュメントの配列ではなく、funding_rounds
フィールドには、個別の資金調達ラウンドである単一のドキュメントの値があります。そのため、4の資金調達ラウンドを持つ企業は、unwind
が4ドキュメントを作成します。ここで、funding_rounds
フィールドを除くすべてのフィールドは正確なコピーであり、これらのコピーのそれぞれの配列ではなく、unwind
が現在処理している会社文書のfunding_rounds
配列の個々の要素になります。したがって、unwind
は、入力として受け取るよりも多くのドキュメントを次のステージに出力する効果があります。これは、project
ステージがfunding_rounds
フィールドを取得することを意味します。このフィールドは、配列ではなく、raised_amount
およびfunded_year
フィールドを持つネストされたドキュメントです。したがって、project
は各企業の複数のドキュメントを受信しますmatch
フィルターを使用して、各ドキュメントを個別に処理し、各資金調達ラウンドの個々の金額と年を識別できます会社。
Mongodb公式ドキュメントによると:
$ unwind入力ドキュメントから配列フィールドを分解して、各要素のドキュメントを出力します。各出力ドキュメントは、配列フィールドの値が要素に置き換えられた入力ドキュメントです。
基本的な例による説明:
コレクションインベントリには、次のドキュメントがあります。
{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }
次の$unwind操作は同等であり、sizesフィールドの各要素のドキュメントを返します。サイズフィールドが配列に解決されないが、欠損、null、または空の配列ではない場合、$ unwindは非配列オペランドを単一要素配列として扱います。
db.inventory.aggregate( [ { $unwind: "$sizes" } ] )
または
db.inventory.aggregate( [ { $unwind: { path: "$sizes" } } ]
上記のクエリ出力:
{ "_id" : 1, "item" : "ABC", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "sizes" : "L" }
{ "_id" : 3, "item" : "IJK", "sizes" : "M" }
なぜそれが必要なのですか?
$ unwindは、集計の実行中に非常に便利です。ソート/検索などのさまざまな操作を実行する前に、複雑な/ネストされたドキュメントを単純なドキュメントに分割します。
$ unwindの詳細:
https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/
集約の詳細を知るには:
https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/
RDBMSの方法に関連する方法で説明させてください。これは声明です:
db.article.aggregate(
{ $project : {
author : 1 ,
title : 1 ,
tags : 1
}},
{ $unwind : "$tags" }
);
document/recordに適用するには:
{
title : "this is my title" ,
author : "bob" ,
posted : new Date () ,
pageViews : 5 ,
tags : [ "fun" , "good" , "fun" ] ,
comments : [
{ author :"joe" , text : "this is cool" } ,
{ author :"sam" , text : "this is bad" }
],
other : { foo : 5 }
}
$ project/Selectは、これらのフィールド/列を単に
[〜#〜] select [〜#〜]著者、タイトル、タグ[〜#〜] from [ 〜#〜]記事
次はMongoの楽しい部分です。この配列tags : [ "fun" , "good" , "fun" ]
「タグ」という名前の別の関連テーブル(値には重複があるため、ルックアップ/参照テーブルにできません)。 SELECTは一般に物事を垂直に生成するので、「タグ」はsplit()をテーブル「タグ」に垂直に戻すことを忘れないでください。
出力をJSONに変換します。
{ "author": "bob", "title": "this is my title", "tags": "fun"},
{ "author": "bob", "title": "this is my title", "tags": "good"},
{ "author": "bob", "title": "this is my title", "tags": "fun"}
Mongoに「_id」フィールドを省略するように指示しなかったため、自動的に追加されます。
重要なのは、集計を実行するためにテーブルのようにすることです。
コレクション内のこのデータを理解するには、以下の例を検討してください
{
"_id" : 1,
"shirt" : "Half Sleeve",
"sizes" : [
"medium",
"XL",
"free"
]
}
クエリ-db.test1.aggregate([{$ unwind: "$ sizes"}]);
出力
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }