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

MongoDB聚合:类数组字符串转换及size按周统计

MongoDB按周统计类数组字符串中Size的数量

问题场景

现有MongoDB文档数据,其中product字段存储为JSON格式的类数组字符串,而非真实嵌套数组,数据示例如下:

[
  {
    "uuid": "yxcvb", 
    "product": "[{\"pid\":\"4f76c06825aa486db9a7a5cedbc2ea19\",\"size\":\"S\"},{\"pid\":\"d3055e0a1bb040dba65674b9733bf4ce\",\"size\":\"M\"}]",
    "timestamp":{"$date":"2023-01-01T11:25:47+00:00"}
  },
  {
    "uuid": "asdfg", 
    "product": "[{\"pid\":\"369b33cc768d496193b18d657d706920\",\"size\":\"M\"}]",
    "timestamp":{"$date":"2023-01-02T11:25:47+00:00"}
  },
  {
    "uuid": "qwert", 
    "product": "[{\"pid\":\"13325cb71fd7413c8f3e18caf20b5d6d\",\"size\":\"S\"},{\"pid\":\"ac431397d49d449cab44d98dc13ec57c\",\"size\":\"M\"},{\"pid\":\"ba35b9f804a44e15bf197d3ef671dc34\",\"size\":\"L\"}]",
    "timestamp":{"$date":"2023-01-03T11:25:47+00:00"}
  }
]

需求是按timestamp的周分组,统计各size的数量,期望输出格式如下:

[
  {
    "week": 52,
    "sizeS": 1
  },
  {
    "week": 52,
    "sizeM": 1
  },
  {
    "week": 1,
    "sizeS": 1
  },
  {
    "week": 1,
    "sizeM": 2
  },
  {
    "week": 1,
    "sizeL": 1
  }
]

解决方案

方案一:使用$jsonParse转换类数组字符串(MongoDB 4.4+)

利用MongoDB 4.4新增的$jsonParse操作符,直接将product字段的JSON字符串解析为真实数组,后续通过标准聚合步骤完成统计:

db.collection.aggregate([
  // 1. 将product的JSON字符串解析为数组
  {
    $addFields: {
      product: { $jsonParse: "$product" }
    }
  },
  // 2. 展开product数组中的每个元素
  { $unwind: "$product" },
  // 3. 提取timestamp对应的ISO周数(2023-01-01属于2022年第52周)
  {
    $addFields: {
      week: { $isoWeek: "$timestamp" }
    }
  },
  // 4. 按周和size分组,统计数量
  {
    $group: {
      _id: { week: "$week", size: "$product.size" },
      count: { $sum: 1 }
    }
  },
  // 5. 格式化输出为期望的键值对结构
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          { week: "$_id.week" },
          { $arrayToObject: [[{ k: { $concat: ["size", "$_id.size"] }, v: "$count" }]] }
        ]
      }
    }
  },
  // 可选:按周排序
  { $sort: { week: 1 } }
])

方案二:正则提取size值(兼容低版本MongoDB)

若无法使用$jsonParse,可通过正则表达式提取所有size的值,再完成统计:

db.collection.aggregate([
  // 1. 用正则提取所有size的值,生成数组
  {
    $addFields: {
      sizes: {
        $map: {
          input: { $regexFindAll: { input: "$product", regex: '"size":"(S|M|L)"' } },
          as: "match",
          in: { $arrayElemAt: ["$$match.captures", 0] }
        }
      }
    }
  },
  // 2. 展开sizes数组
  { $unwind: "$sizes" },
  // 3. 提取ISO周数
  {
    $addFields: {
      week: { $isoWeek: "$timestamp" }
    }
  },
  // 4. 按周和size分组统计
  {
    $group: {
      _id: { week: "$week", size: "$sizes" },
      count: { $sum: 1 }
    }
  },
  // 5. 格式化输出结构
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          { week: "$_id.week" },
          { $arrayToObject: [[{ k: { $concat: ["size", "$_id.size"] }, v: "$count" }]] }
        ]
      }
    }
  },
  { $sort: { week: 1 } }
])

说明

  • $isoWeek返回日期对应的ISO周数,符合示例中2023-01-01为第52周的结果;
  • 方案二中的正则可根据实际size取值范围调整(如包含XL等);
  • 最终输出通过$arrayToObject和$mergeObjects将统计结果转换为期望的键名格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:35:30