You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合分组如何实现formName-年份-月份层级嵌套数组结构

解决方案

完整聚合语句

db.FormsStore.aggregate([
  // 保留原有过滤条件
  {$match:{myKey:"a guid to group my forms together"}},
  // 统一不同名的日期字段,转换为标准日期类型
  {
    $addFields: {
      updateDate: {
        $dateFromString: {
          dateString: { $ifNull: ["$updatedAt", "$lastUpdated"] }
        }
      }
    }
  },
  // 第一重分组:按表单名+年份+月份去重,避免重复的年月数据
  {
    $group: {
      _id: {
        formName: "$formName",
        year: { $year: "$updateDate" },
        month: { $month: "$updateDate" }
      }
    }
  },
  // 可选:按年份、月份升序排列,输出的层级会按时间顺序展示
  {
    $sort: {
      "_id.year": 1,
      "_id.month": 1
    }
  },
  // 第二重分组:按表单名+年份聚合,生成月份层级的子节点
  {
    $group: {
      _id: {
        formName: "$_id.formName",
        year: "$_id.year"
      },
      children: { $push: { text: "$_id.month" } }
    }
  },
  // 第三重分组:按表单名聚合,生成年份层级的子节点
  {
    $group: {
      _id: "$_id.formName",
      children: { $push: { text: "$_id.year", children: "$children" } }
    }
  },
  // 格式化输出为要求的结构
  {
    $project: {
      _id: 0,
      text: "$_id",
      children: 1
    }
  }
])

核心逻辑说明

  • 用$ifNull兼容两种不同的日期字段名,统一转换为日期类型的updateDate字段,解决字段名不一致的问题
  • 采用从细到粗的三层分组逻辑,先聚合最细粒度的「表单+年+月」,再依次向上生成年份、表单层级的结构,不会出现年月数据错位的问题
  • 可选的$sort步骤可以保证输出的年份、月份都是按时间顺序排列,不需要后续二次处理

C# 调用说明

使用官方MongoDB.Driver时,可以直接将上述管道每一步转为BsonDocument对象传入Aggregate方法即可,示例参考:

var pipeline = new BsonDocument[]
{
    BsonDocument.Parse("{ $match:{myKey:\"a guid to group my forms together\"} }"),
    // 依次填入其他管道步骤的BsonDocument即可
};
var result = await mongoDatabase.GetCollection<BsonDocument>("FormsStore")
    .AggregateAsync<BsonDocument>(pipeline);

也可以直接用LINQ语法构造对应分组逻辑,和原生聚合的执行效率没有差异。


内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 16:54:03