【问题标题】:Include all existing fields and add new fields to document包括所有现有字段并将新字段添加到文档
【发布时间】:2013-10-26 05:47:30
【问题描述】:

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

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

【问题讨论】:

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

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

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

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

【讨论】:

  • 知道如何在 C# 驱动程序中使用它吗?好像不存在
  • 我不熟悉 C# 驱动程序,但 $addFields 是 MongoDB 3.4 中的新功能,由 C# driver version 2.5+ 支持
  • 我一直在寻找一种在 C# 驱动程序中执行此操作的方法,到目前为止,执行此操作的方法似乎是使用类似 IAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
  • 我发现如果你指定相同的字段名称它甚至可以替换一个字段
【解决方案2】:

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

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

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

【讨论】:

  • 但这将创建一个名为 document 的嵌入式文档,如果选择创建一个合并文档会更好...
  • 有谁知道在不创建嵌入式文档的情况下传递所有键值对的解决方案?
  • 屏住呼吸。 MongoDB 3.4 将附带$addFields aggregation stage,它就是这样做的。见stackoverflow.com/a/24557029/4653485
  • 这似乎是当前最好的解决方案,因为您可以(至少在 JS 中)然后使用扩展运算符重建原始对象并附加新的custom_fieldconst newObj = { ...result.document, custom_field: result.custom_field }
【解决方案3】:

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

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

【讨论】:

  • ...因为创建聚合主要是为了对集合字段中的数据进行分组/计算...事实上最好的答案!
  • 您有一个集合posts,其中包含_id、标题、正文、喜欢字段。 likes 字段是一个喜欢帖子的用户 _id 的数组。你怎么能列出所有带有_id、标题、正文、likeCount 的帖子?在这种情况下,返回所有字段是一个直接目的。
【解决方案4】:

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

from docs

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

db.collection.aggregate([

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

【讨论】:

    【解决方案5】:

    截至 2.6.4 版本,Mongo DB 没有 $project 聚合管道的此类功能。来自docs$project

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

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

    【讨论】:

      【解决方案6】:

      根据@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);
      

      【讨论】:

        猜你喜欢
        • 2020-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-12
        • 1970-01-01
        • 2021-12-08
        相关资源
        最近更新 更多