次のパイプラインが機能するはずです:
var pipeline = [
{
"$project": {
"title": 1, "body": 1,
"post_id": { "$ifNull": [ "$_post", "$_id" ] }
}
},
{
"$group": {
"_id": "$post_id",
"title": { "$first": "$title" },
"body": { "$first": "$body" },
"comments": {
"$push": {
"_id": "$_id",
"_post": "$post_id",
"body": "$body"
}
}
}
},
{
"$project": {
"title": 1, "body": 1,
"comments": {
"$setDifference": [
{
"$map": {
"input": "$comments",
"as": "el",
"in": {
"$cond": [
{ "$ne": [ "$$el._id", "$$el._post" ] },
"$$el",
false
]
}
}
},
[false]
]
}
}
}
];
Post.aggregate(pipeline, function (err, result) {
if (err) { /* handle error */ };
console.log(result);
});
パイプラインは、最初のステップである $ project
オペレーターステージは、フィールド post_id
を投影することです 次のパイプラインステージでgroupbyキーとして使用されます。スキーマは階層的であるため、親/ルートドキュメントにはこのフィールドが必要です。 $ ifNull
演算子は合体演算子として機能し、フィールドがドキュメントに存在しない場合は置換値を返します。
次のパイプラインステップ、 $ group
パイプラインステージは、データをグループ化して処理しようとします。 $ group
パイプライン演算子は、SQLのGROUPBY句に似ています。 SQLでは、集計関数を使用しない限り、GROUPBYを使用することはできません。同様に、MongoDBでも集計関数を使用する必要があります。この場合、 <が必要です。 code> $ push
コメント配列を作成する演算子。他のフィールドは、 $ first
オペレーター。
最後のステップでは、コメント配列をフィッティングして、投稿の詳細を含むドキュメントを削除します。これは、コメントタイプではありません。これは、 <によって可能になります。 code> $ setDifference
および $ map
$ map
本質的に、演算子は、配列の各要素の部分式で評価されたロジックの結果として値を保持する新しい配列フィールドを作成します。 $ setDifference
次に、演算子は、最初のセットには表示されるが2番目のセットには表示されない要素を含むセットを返します。つまり、最初のセットに対して2番目のセットの相対的な補数を実行します。この場合、最後のコメント
が返されます _id
を介して親ドキュメントに関連しない要素を持つ配列 プロパティ。