150

我想定义一个 $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

6 回答 6

208

在 4.2+ 中,您可以使用$set聚合管道运算符,它只是$addFields在 3.4 中添加的别名

$addFields阶段相当于$project明确指定输入文档中所有现有字段并添加新字段的阶段。

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])
于 2016-11-25T21:07:36.170 回答
85

您可以使用$$ROOT来引用根文档。将此文档的所有字段保存在一个字段中,然后尝试获取它(取决于您的客户端系统:Java、C++、...)

 [
    {
        $project: {
            custom_field: "$obj.obj_field1",
            document: "$$ROOT"

        }
    },
    ... //group, match, and whatever...
]
于 2015-01-02T09:01:41.940 回答
7

>>> 在这种情况下我可以使用“包含所有字段”关键字或其他解决方案吗?

不幸的是,聚合操作中没有运算符可以“包含所有字段”。唯一的原因是,因为创建聚合主要是为了对集合字段(sum、avg 等)中的数据进行分组/计算并返回所有集合的字段,这不是直接目的。

于 2013-11-26T10:55:16.660 回答
4

要将新字段添加到文档中,您可以使用$addFields

来自文档

对于文档中的所有字段,您可以使用 $$ROOT

db.collection.aggregate([

{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
        _id : "$field1",
        data: { $push : "$$ROOT" }
    }}
])
于 2019-07-24T09:08:49.433 回答
3

从 2.6.4 版本开始,Mongo DB 没有针对$project聚合管道的此类功能。从文档$project

将仅具有指定字段的文档传递到管道中的下一个阶段。指定的字段可以是输入文档中的现有字段或新计算的字段。

默认情况下,_id 字段包含在输出文档中。要将输入文档中的其他字段包含在输出文档中,您必须在 $project 中明确指定包含。

于 2014-08-21T02:49:37.140 回答
0

根据@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);
于 2018-03-05T20:32:31.043 回答