【问题标题】:Using $addFields in MongoDB Driver for C#在 C# 的 MongoDB 驱动程序中使用 $addFields
【发布时间】:2019-01-23 17:57:21
【问题描述】:

我知道这不是一项功能,不会按照此处所述实现:https://jira.mongodb.org/browse/CSHARP-1750

但是我确实需要使用 $addFields 运算符执行聚合。 根据How to use Addfields in MongoDB C# Aggregation Pipeline的评论

jira.mongodb.org/browse/CSHARP-1750。阅读“无法解决”的决议。 给出了理由,但显然根本不在路线图上。如果 你真的想要它然后手动指定管道 BsonDocument 构建器,因为这实际上是所有 API 方法 反正。和/或投票支持 JIRA 问题,并有足够的支持 那么也许有人会认为它值得考虑未来的工作。 – 尼尔·伦恩 2018 年 11 月 3 日

您可以手动构建管道。我将如何去做,我可以使用我之前的聚合,可能在手动字符串之后,所以我不必手动构建整个东西,而只需要 addFields 部分?

我试过了

StringBuilder addFieldsDefinition = new StringBuilder();
addFieldsDefinition.AppendLine("{");
addFieldsDefinition.AppendLine("\"values"":{$reduce: {");
addFieldsDefinition.AppendLine("input: \"$values\",");
addFieldsDefinition.AppendLine("initialValue: {timeStamp: ISODate(\"0000-01-01T00:00:00.000+0000\")},");
addFieldsDefinition.AppendLine("in: {$cond: [{$and : [");
addFieldsDefinition.AppendLine("{$gte : [\"$$this.timeStamp\", \"$$value.timeStamp\"]},");
addFieldsDefinition.AppendLine("{$lte : [\"$$this.timeStamp\", ISODate(\"" + dt.ToString("yyyy-MM-dd") + "T" + dt.ToString("HH:mm:ss.fff") + "\")]}");
addFieldsDefinition.AppendLine("]}, \"$$this"", \"$$value\"]}");
addFieldsDefinition.AppendLine("}}");
addFieldsDefinition.AppendLine("}");

IAggregateFluent<BsonDocument> aggregate = col.Aggregate()
  .Match(filterDef)
  .Project(projectDef);
aggregate.Stages.Add("$addFields : " + addFieldsDefinition .ToString());

想要获取 Array 中的元素,其中子文档中的“timeStamp”字段最高但低于指定的 dateTime。 但是当我尝试添加舞台时,代码向我抛出了一个异常,说字符串无法转换为 IPipelineStageDefinition。

我不想做这样的内置聚合(伪代码)

.Unwind(values).Match(timestamp < dt).Sort(timeStamp).Limit(1)

因为那太慢了。

编辑:

我现在使用 MongoDB.Bson 对象来创建舞台: VB.NET 代码(抱歉,我懒得手动转换那个乱七八糟的东西)

Dim stage As New BsonDocument(New BsonElement("$addFields", New BsonDocument(New BsonElement("value",
    New BsonDocument(New BsonElement("$reduce", New BsonDocument(New List(Of BsonElement) From
        {
            New BsonElement("input", New BsonString("$" + FieldNames.VALUES_FIELDNAME)),
            New BsonElement("initialValue", New BsonDocument(New BsonElement("timeStamp", New BsonDateTime(DateTime.MaxValue)))),
            New BsonElement("in", New BsonDocument(New List(Of BsonElement) From
                {
                    New BsonElement("$cond", New BsonArray() From
                    {
                        New BsonDocument(New BsonElement("$and", New BsonArray() From
                        {
                            New BsonDocument(New BsonElement("$lte", New BsonArray() From {New BsonString("$$this.timeStamp"), New BsonString("$$value.timeStamp")})),
                            New BsonDocument(New BsonElement("$gte", New BsonArray() From {New BsonString("$$this.timeStamp"), New BsonDateTime(dt)}))
                        })),
                        New BsonString("$$this"),
                        New BsonString("$$value")
                    })
                }
            ))
        }
    ))))
)))

【问题讨论】:

  • 嗨..你为什么不使用 Mongodb.Driver.Linq ?所以你使用 Linq 语法?
  • @federicoscamuzzi:我怀疑是因为 OP 认为不可能使用 linq 语法。也许添加一个答案来说明如果你知道的话。
  • 我对 Linq 不太满意。即便如此,在 VB.Net 中,它更糟糕,可读性更差。

标签: c# mongodb


【解决方案1】:

BsonDocument 可以转换为 IPipelineStageDefinition。要获得您想要的 BsonDocument:

var addFieldsDefinitionDoc = BsonDocument.Parse(addFieldsDefinition.ToString());
var stageElement = new BsonElement("$addFields", addFieldsDefinitionDoc);
var stage = new BsonDocument(stageElement)

然后添加它只需使用:

aggregate = aggregate.AppendStage(stage);

我不确定aggregate.Stages.Add 是否会这样做,但我认为 AppendStage 可能是更好的方法(尽管我没有找到任何文档告诉我做大多数事情的正确方法是通过反复试验和检查源代码以了解事情的工作原理)...

您甚至可以使用普通的阶段构建器函数添加额外的阶段,如下所示:

aggregate = aggregate.Project(projectionDefinition);

甚至

aggregate = aggregate
    .AppendStage(stage)
    .Project(projectionDefinition);

【讨论】:

  • 啊,这似乎行得通。不幸的是 BsonDocument.Parse 没有吞下 ISODate() 字符串。但是我可以通过根据需要添加元素来构建没有字符串构建器的 BsonDocument。谢谢你的回答。
  • 啊,是的。我在测试时注意到了 ISODate 的事情。问题似乎是你的初始日期。如果您将年份从 0000 更改为 0001,那么它开始为我正确解析。
  • 我设法通过使用 BsonDocument、BsonElements、BsonArrays 和 BsonStrings 完成整个工作来使其正常工作。但是它似乎没有执行我添加的聚合阶段。
  • 刚刚快速浏览了文档,我怀疑它实际上可能需要aggregate = aggregate.AppendStage(stage); 而不仅仅是我使用的行。你这样做了吗?我无法查看我当前的代码来确认我现在在工作代码中所做的事情,但我会尽量记住早上检查并酌情更新答案。
  • 确实是解决方案。谢谢。
猜你喜欢
  • 1970-01-01
  • 2023-03-02
  • 1970-01-01
  • 2016-03-13
  • 2016-09-09
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多