すべての既存フィールドをリストすることなく、新しいフィールドを追加してすべての既存フィールドを含めるように指示できる$ project集計ステージを定義したいと思います。
私の文書は次のようになり、多くのフィールドがあります。
{
obj: {
obj_field1: "hi",
obj_field2: "hi2"
},
field1: "a",
field2: "b",
...
field26: "z"
}
次のような集計操作を行います。
[
{
$project: {
custom_field: "$obj.obj_field1",
//the next part is that I don't want to do
field1: 1,
field2: 1,
...
field26: 1
}
},
... //group, match, and whatever...
]
この場合に使用できる「すべてのフィールドを含める」キーワード、またはすべてのフィールドを個別にリストする必要のない他の方法のようなものはありますか?
4.2以降では、 $set
に追加する集約パイプライン演算子 $addFields
へのエイリアス以外は使用できません
$addFields
ステージは、入力ドキュメント内のすべての既存フィールドを明示的に指定して新しいフィールドを追加する$project
ステージと同等です。
db.collection.aggregate([
{ "$addFields": { "custom_field": "$obj.obj_field1" } }
])
$$ ROOT を使用して、ルートドキュメントを参照できます。このドキュメントのすべてのフィールドをフィールドに保持し、その後取得しようとします(クライアントシステムによって異なります:Java、C++、...)
[
{
$project: {
custom_field: "$obj.obj_field1",
document: "$$ROOT"
}
},
... //group, match, and whatever...
]
>>>この場合や他のソリューションで使用できる「すべてのフィールドを含める」キーワードのようなものがありますか?
残念ながら、集計操作に「すべてのフィールドを含める」演算子はありません。集計は主にコレクションフィールド(sum、avgなど)からのデータをグループ化/計算し、コレクションのすべてのフィールドを返すために作成されるため、唯一の理由は直接的な目的ではありません。
バージョン2.6.4の時点で、Mongo DBには$project
集約パイプラインのためのそのような機能がありません。 docs for $project
から:
指定されたフィールドのみを持つドキュメントをパイプラインの次のステージに渡します。指定されたフィールドは、入力ドキュメントの既存のフィールドまたは新しく計算されたフィールドです。
そして
デフォルトでは、_idフィールドは出力ドキュメントに含まれます。入力ドキュメントのその他のフィールドを出力ドキュメントに含めるには、$ projectに含めることを明示的に指定する必要があります。
ドキュメントに新しいフィールドを追加するには、$ addFieldsを使用できます
[ドキュメントから] [1]
文書内のすべてのフィールドに対して、$$ ROOTを使用できます
db.collection.aggregate([
{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
_id : "$field1",
data: { $Push : "$$ROOT" }
}}
])
[1]: https://docs.mongodb.com/master/reference/operator/aggregation/addFields/
@Dekaの回答によると、c#mongodb driver 2.5の場合、以下のようなすべてのキーを持つグループ化されたドキュメントを取得できます。
var group = new BsonDocument
{
{ "_id", "$groupField" },
{ "_document", new BsonDocument { { "$first", "$$ROOT" } } }
};
ProjectionDefinition<BsonDocument> projection = new BsonDocument{{ "document", "$_document"}};
var result = await col.Aggregate().Group(group).Project(projection).ToListAsync();
// For demo first record
var fistItemAsT = BsonSerializer.Deserialize<T>(result.ToArray()[0]["document"].AsBsonDocument);