包括所有现有字段并向文档添加新字段


123

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

在这种情况下,是否可以使用类似“包括所有字段”这样的关键字,或者可以通过其他方式避免单独列出每个字段?


1
下一个主要版本2.6中将提供此功能。您可以在不稳定的dev分支上尝试使用-使用“ $$ ROOT”来引用整个传入文档。请参阅此票证中的详细信息:jira.mongodb.org/browse/SERVER-5916
Asya Kamsky

1
stackoverflow.com/questions/20497499/…上也提出了此问题,并提供了一些其他有用且不同的答案。
文斯·鲍德伦

Answers:


168

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

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

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])

2
知道如何在C#驱动程序中使用它吗?似乎不存在
Homam

我不熟悉C#驱动程序,但是$addFields它是MongoDB 3.4中的新功能,而C#驱动程序2.5+版本
styvane

我一直在寻找在C#驱动程序中执行此操作的方法,到目前为止,看起来执行此操作的方法将是使用类似的方法IAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse

4
我发现,如果您指定相同的字段名称,它甚至可以替换一个字段
CME64 '18

79

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

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

        }
    },
    ... //group, match, and whatever...
]

17
但是,这将创建一个称为document选项的嵌入式文档,以创建一个合并的文档会更好……
Alexander Suraphel

2
有谁知道不创建嵌入式文档即可通过所有键值对的解决方案?
ugotchi

11
屏住呼吸。MongoDB 3.4将带有$ addFields聚合阶段来执行此操作。请参阅stackoverflow.com/a/24557029/4653485
杰罗姆

这似乎是当前最好的解决方案,因为您可以(至少在JS中)然后使用传播操作符来重建带有新custom_field附件的原始对象。const newObj = { ...result.document, custom_field: result.custom_field }
ffritz

7

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

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


...因为主要是创建汇总来对集合字段中的数据进行分组/计算...实际上是最佳答案!
felipsmartins '16

1
您有一个posts包含_id,标题,正文,喜欢字段的集合。Likes字段是喜欢帖子的_id用户数组。您如何列出所有带有_id,标题,正文和likeCount的帖子?在这种情况下,返回所有字段是直接目的。
doc_id

3

从2.6.4版开始,Mongo DB的$project聚合管道没有此功能。从文档中获取$project

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

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


2

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

来自docs

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

db.collection.aggregate([

{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
        _id : "$field1",
        data: { $push : "$$ROOT" }
    }}
])

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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.