2つのコレクションがあります。 1つは、もう1つへの参照を追加し、戻り時にそれを設定したいです。
これは私が結果として達成しようとしているjsonの例です:
{
"title": "Some Title",
"uid": "some-title",
"created_at": "1412159926",
"updated_at": "1412159926",
"id": "1",
"metadata": {
"date": "2016-10-17",
"description": "a description"
},
"tags": [
{
"name": "Tag 1",
"uid": "tag-1"
},
{
"name": "Tag 2",
"uid": "tag-2"
},
{
"name": "Tag 3",
"uid": "tag-3"
}
]
}
これが私のクローズを取得するmongoクエリですが、_id
オブジェクト内のアイテムの元の本文をネストしています。
db.tracks.aggregate([{
$unwind: "$tags"
}, {
$lookup: {
from: "tags",
localField: "tags",
foreignField: "_id",
as: "tags"
}
}, {
$unwind: "$tags"
}, {
$group: {
"_id": {
"title": "$title",
"uid": "$uid",
"metadata": "$metadata"
},
"tags": {
"$Push": "$tags"
}
}
}])
結果はこれです:
{
"_id" : {
"title" : "Some Title",
"uid" : "some-title",
"metadata" : {
"date" : "2016-10-17",
"description" : "a description"
}
},
"tags" : [
{
"_id" : ObjectId("580499d06fe29ce7093fb53a"),
"name" : "Tag 1",
"uid" : "tag-1"
},
{
"_id" : ObjectId("580499d06fe29ce7093fb53b"),
"name" : "Tag 2",
"uid" : "tag-2"
}
]
}
望ましい出力を達成する方法はありますか?また、返したいすべてのフィールドを$group
で定義する必要がない方法があります。元のオブジェクトを返したいのですが、tags
配列の参照ドキュメントを使用します。
最初に元のドキュメントをtags
配列フィールドにピボットしました。これは、ドキュメントが非正規化されることを意味します。$group
パイプラインは、 _id
フィールドを_id
キーとして使用し、$first
または$last
演算子。
グループパイプライン演算子は、SQLのGROUP BY
句に似ています。 SQLでは、集計関数を使用しない限り、GROUP BY
を使用できません。同様に、MongoDBでも集計関数を使用する必要があるため、残念ながら$group
パイプラインで定義する必要がない他の方法はありません。 $first
または$last
を使用しないで返したいすべてのフィールド=各フィールドの演算子:
db.tracks.aggregate([
{ "$unwind": "$tags" },
{
"$lookup": {
"from": "tags",
"localField": "tags",
"foreignField": "_id",
"as": "resultingArray"
}
},
{ "$unwind": "$resultingArray" },
{
"$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"uid": { "$first": "$uid" },
"created_at": { "$first": "$created_at" },
"updated_at": { "$first": "$updated_at" },
"id": { "$first": "$id" },
"metadata": { "$first": "$metadata" },
"tags": { "$Push": "$resultingArray" }
}
}
])
予期しない結果をもたらすパイプラインをデバッグする場合に常に使用する1つのトリックは、最初のパイプライン演算子だけで集計を実行することです。期待どおりの結果が得られた場合は、次を追加します。
上記の答えでは、最初に$unwind
だけを集計してみます。それが機能する場合は、$lookup
を追加します。これにより、問題の原因となっているオペレーターを絞り込むことができます。この場合、$group
が問題の原因であると考えているため、最初の3つのステップだけでパイプラインを実行し、結果のドキュメントを検査できます。そのパイプライン:
db.tracks.aggregate([
{ "$unwind": "$tags" },
{
"$lookup": {
"from": "tags",
"localField": "tags",
"foreignField": "_id",
"as": "resultingArray"
}
},
{ "$unwind": "$resultingArray" }
])
出力を生成します
/* 1 */
{
"_id" : ObjectId("5804a6c900ce8cbd028523d9"),
"title" : "Some Title",
"uid" : "some-title",
"created_at" : "1412159926",
"updated_at" : "1412159926",
"id" : "1",
"metadata" : {
"date" : "2016-10-17",
"description" : "a description"
},
"resultingArray" : {
"name" : "Tag 1",
"uid" : "tag-1"
}
}
/* 2 */
{
"_id" : ObjectId("5804a6c900ce8cbd028523d9"),
"title" : "Some Title",
"uid" : "some-title",
"created_at" : "1412159926",
"updated_at" : "1412159926",
"id" : "1",
"metadata" : {
"date" : "2016-10-17",
"description" : "a description"
},
"resultingArray" : {
"name" : "Tag 2",
"uid" : "tag-2"
}
}
/* 3 */
{
"_id" : ObjectId("5804a6c900ce8cbd028523d9"),
"title" : "Some Title",
"uid" : "some-title",
"created_at" : "1412159926",
"updated_at" : "1412159926",
"id" : "1",
"metadata" : {
"date" : "2016-10-17",
"description" : "a description"
},
"resultingArray" : {
"name" : "Tag 3",
"uid" : "tag-3"
}
}
検査から、各入力ドキュメントについて、最後のパイプラインは3つのドキュメントを出力することがわかります。ここで、3は計算フィールドresultingArray
の配列要素の数であり、それらすべてに共通の_id
と他のフィールドがあります異なる[resultingArray
]フィールドを除いて、_id
フィールドでドキュメントをグループ化するパイプラインを追加し、その後- $first
または$last
演算子、与えられたソリューションのように:
db.tracks.aggregate([
{ "$unwind": "$tags" },
{
"$lookup": {
"from": "tags",
"localField": "tags",
"foreignField": "_id",
"as": "resultingArray"
}
},
{ "$unwind": "$resultingArray" },
{
"$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"uid": { "$first": "$uid" },
"created_at": { "$first": "$created_at" },
"updated_at": { "$first": "$updated_at" },
"id": { "$first": "$id" },
"metadata": { "$first": "$metadata" },
"tags": { "$Push": "$resultingArray" }
}
}
])