如何使用 JSONata 对 JSON 响应进行分组聚合与结构重写

13次阅读

如何使用 JSONata 对 JSON 响应进行分组聚合与结构重写

本文详解如何利用 jsonata 的上下文变量(特别是 $$)对嵌套数组执行按字段分组、数值聚合及结果结构重塑,解决常见分组求和失败问题。

在 API 集成或数据管道中,常需将原始 jsON 响应按某字段(如 enterpriseid)分组,并对数值字段(如 bookingvalue)求和,最终输出结构化的新格式。jsonata 是轻量高效的选择,但其上下文切换机制易被忽略——尤其在嵌套操作(如 $distinct 内调用 $Filter)中,若不显式回溯根节点,$filter 将在错误上下文中执行,导致聚合失效。

以下为正确实现方案:

✅ 正确 JSONata 查询(带注释)

{   "output": $distinct(response.{     "enterpriseid": enterpriseid,     "enterprise": enterprise,     "bookingvalue": $sum(       $filter($$.response, function($item) {          $item.enterpriseid = enterpriseid        }).bookingvalue     )   }) }

? 关键点解析:

  • $$.response:$$ 指向原始输入 JSON 的根对象,确保 $filter 总是遍历完整 response 数组,而非当前迭代项的子属性;
  • $distinct(…):基于对象字面量中的 enterpriseid 和 enterprise 自动去重(因同 ID 企业名称一致),天然实现分组;
  • $sum(…) + $filter(…):对每个唯一 enterpriseid,筛选出所有匹配项并累加 bookingvalue(支持小数,如 46 + 275 + 199.5 = 520.5)。

⚠️ 常见错误与规避

  • ❌ 错误写法:$filter(response, …) —— 此时 response 在 $distinct 内部被解析为当前迭代对象(非数组),导致过滤失败;
  • ✅ 正确写法:$filter($$.response, …) —— 强制回到根路径,获取完整数组;
  • ? 提示:当嵌套多层(如 data.items.response)时,始终用 $$ 显式指定源路径,避免隐式上下文歧义。

? 验证与调试建议

  1. JSONata Exerciser 中粘贴原始 JSON 与上述查询,实时查看结果;
  2. 分步调试:先测试 $$.response.enterpriseid 确认根访问正常,再逐步组合 $filter 和 $sum;
  3. 若企业名称存在空格/换行(如示例中 ” Absolute F and B…”),聚合逻辑不受影响,但导出至下游系统前建议用 $trim(enterprise) 清理。

通过精准控制上下文,JSONata 不仅能完成基础投影,更能胜任分组聚合、条件映射等 etl 核心任务——无需编写 javaScript,一行声明式表达式即可生成生产就绪的数据结构

text=ZqhQzanResources