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

如何用MongoDB/Mongoose.js按月份分组统计标签数量?

解决MongoDB按月份分组统计各标签数量的问题

你说得没错,确实得用聚合查询来实现这个按月份统计各标签数量的需求~你的现有代码已经走对了第一步,但还没处理标签的拆分和多标签统计的部分,我来帮你调整一下:

核心思路

要实现按月份统计每个标签的数量,需要先把tags数组拆分成单个标签条目,再关联获取标签名称(毕竟你要的是tag1、tag2这样的标签名而非ObjectId),之后按「月份+标签」分组计数,最后把同一个月的所有标签统计结果合并成一个文档。

完整聚合查询代码

const monthAbbrs = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; // 月份缩写数组,按需改成全称也可以

Post.aggregate([
  // 1. 过滤时间范围(注意字段是date还是created_at,你的集合结构里是date,这里统一用date)
  {
    $match: {
      date: {
        $gt: oneYearFromNow,
        $lt: dateNow
      }
    }
  },
  // 2. 拆分tags数组,每个标签对应一条记录
  { $unwind: "$tags" },
  // 3. 关联Tag集合,获取标签的名称(假设Tag集合有name字段,根据你的实际字段调整)
  {
    $lookup: {
      from: "tags", // Tag集合的名称
      localField: "tags.id",
      foreignField: "_id",
      as: "tagInfo"
    }
  },
  // 4. 把关联后的tagInfo数组拆成单个对象,方便后续使用
  { $unwind: "$tagInfo" },
  // 5. 先按「年份+月份+标签名」分组,统计每个月每个标签的数量
  {
    $group: {
      _id: {
        year: { $year: "$date" },
        month: { $month: "$date" },
        tagName: "$tagInfo.name"
      },
      count: { $sum: 1 }
    }
  },
  // 6. 再按「年份+月份」分组,把同一个月的所有标签统计结果收集成数组
  {
    $group: {
      _id: {
        year: "$_id.year",
        month: "$_id.month"
      },
      tagCounts: {
        $push: {
          k: "$_id.tagName",
          v: "$count"
        }
      }
    }
  },
  // 7. 把tagCounts数组转成键值对对象,同时处理月份显示
  {
    $project: {
      _id: 0,
      month: { $arrayElemAt: [monthAbbrs, "$_id.month"] },
      // 把标签计数数组转成对象,比如{tag1:5, tag2:80}
      tagCounts: { $arrayToObject: "$tagCounts" }
    }
  },
  // 8. 把tagCounts里的字段展开到根文档(可选,如果你不想嵌套在tagCounts里的话)
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: ["$tagCounts", { month: "$month" }]
      }
    }
  },
  // 可选:按月份排序
  { $sort: { "_id.year": 1, "_id.month": 1 } }
])

关键步骤说明

  • $unwind:拆分tags数组是核心,因为每个Post可能包含多个标签,只有拆分后才能单独统计每个标签的数量。
  • $lookup:关联Tag集合是为了获取标签的名称,毕竟直接用ObjectId作为字段名没意义,如果你已经在Post的tags里存储了标签名称,这一步可以省略。
  • 两次$group:第一次分组是统计「每个月每个标签」的数量,第二次是把同一个月的所有标签统计结果合并,方便转成你要的键值对格式。
  • $arrayToObject + $replaceRoot:这两步是把标签计数的数组转成tag1:5这样的字段格式,实现你想要的输出结构。

注意事项

  • 确保Tag集合的名称和字段名(比如name)和你的实际数据一致,否则需要调整$lookup的参数。
  • 时间过滤部分,你的原代码里混用了created_at和date,要和集合里的字段保持一致(你的集合结构里是date)。
  • 月份字符串数组可以按需改成全称(比如你的原数组monthStrings),只要对应索引正确就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:57:42