MongoDB C# 驱动程序:将时间桶转换为以键作为桶时间的字典

问题描述 投票:0回答:1

我们有一个文档集合,其架构总结了日常交易。

{
  "licenseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "transactionDay":"2023-08-23",
  "startTime": "2023-08-23T13:00:00Z",
  "endTime": "2023-08-23T13:01:00Z",
  "count": 1,
  "size": 12345
}

我们需要生成具有以下模式的报告,该报告提供字典结构中

count
size
字段的每日总计,其中键作为
transactionDay
值。

{
  "licenseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "usage": {
    "2023-08-23": {
      "countTotal": 1,
      "sizeTotal": 12345
    }
  }
}

使用 C# MongoDB 驱动程序 v2.21,我们可以使用 Aggregator Fluent 语法生成包含每日摘要的报告,但不是我们要求的格式。

var usageReport = transactionCollection.Aggregate()
    .Match(licenseFilter)
    .Group(
        e => e.transactionDay,
        g => new
        {
            transactionDay= g.Key,
            licenseId= g.First().licenseId,
            sizeTotal= g.Sum(x=>x.size),
            countTotal= g.Sum(x=>x.count)
        })
    .ToList();

尚不清楚我们是否缺少投影阶段,或者我们在

Group
中采取的方法是否不正确。

任何关于如何实现这一目标的指示或参考将不胜感激。

c# mongodb aggregation-framework mongodb-.net-driver
1个回答
1
投票

MongoDB 聚合管道应如下所示:

  1. $match
    - 过滤阶段

  2. $group
    - 按
    transactionDay
    分组并执行计算。

  3. $group
    - 按
    licenseId
    分组并构建
    transactionDays
    数组。

  4. $project
    - 装饰输出文档。通过
    transactionDays
    $arrayToObject
    数组转换为键值对。

[
  {
    $match: {
      "licenseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  },
  {
    $group: {
      _id: "$transactionDay",
      licenseId: {
        $first: "$licenseId"
      },
      countTotal: {
        $sum: "$count"
      },
      sizeTotal: {
        $sum: "$size"
      }
    }
  },
  {
    $group: {
      _id: "$licenseId",
      transactionDays: {
        $push: {
          k: "$_id",
          v: {
            countTotal: "$countTotal",
            sizeTotal: "$sizeTotal"
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      licenseId: "$_id",
      usage: {
        $arrayToObject: "$transactionDays"
      }
    }
  }
]

演示@Mongo Playground


您的预期结果的模型类应如下所示:

[BsonNoId]
public class UsageReport
{
    public Guid licenseId { get; set; }
    public Dictionary<string, UsageDate> usage { get; set; }
}

public class UsageDate
{
    public int countTotal { get; set; }
    public int sizeTotal { get; set; }
}

对于 Aggregate Fluent 语法,应如下所示:

PipelineStageDefinition<Transaction, Transaction> firstStage 
    = PipelineStageDefinitionBuilder.Match(licenseFilter);

PipelineStageDefinition<Transaction, BsonDocument> secondStage
    = PipelineStageDefinitionBuilder.Group<Transaction, BsonDocument>(new BsonDocument
    {
        { "_id", "$transactionDay" },
        { "licenseId", new BsonDocument 
            { 
                { "$first", "$licenseId" } 
            } 
        },
        { "sizeTotal", new BsonDocument
            {
                { "$sum", "$size" }
            }
        },
        { "countTotal", new BsonDocument
            {
                { "$sum", "$count" }
            }
        }
    });

PipelineStageDefinition<BsonDocument, BsonDocument> thirdStage
    = PipelineStageDefinitionBuilder.Group<BsonDocument, BsonDocument>(new BsonDocument
    {
        { "_id", "$licenseId" },
        { "transactionsDays", new BsonDocument 
            { 
                { "$push", new BsonDocument
                    {
                        { "k", "$_id" },
                        { "v", new BsonDocument
                            {
                                { "countTotal", "$countTotal" },
                                { "sizeTotal", "$sizeTotal" }
                            }
                        }
                    }
                } 
            } 
        }
    });

PipelineStageDefinition<BsonDocument, UsageReport> forthStage
    = PipelineStageDefinitionBuilder.Project<BsonDocument, UsageReport>(new BsonDocument
    {
        { "_id", 0 },
        { "licenseId", "$_id" },
        { "usage", new BsonDocument("$arrayToObject", "$transactionsDays") }
    });

var usageReport = _collection.Aggregate()
    .AppendStage(firstStage)
    .AppendStage(secondStage)
    .AppendStage(thirdStage)
    .AppendStage(forthStage)
    .ToList();
© www.soinside.com 2019 - 2024. All rights reserved.