如何在jq函数中使用传入的键参数构造对象
问题描述
我经常需要在jq中创建可复用的函数,对输入的指定字段执行转换操作。比如尝试写过这两个函数:
示例函数1:仅保留指定字段
def keep_field_only(field): {field} ;
示例函数2:按指定字段统计数量
def count_by(field): group_by(field) | map( { field: .[0].field, count: length } ) ;
问题在于:group_by(field)能正常使用传入的字段参数,但用这个参数构造对象(比如仅保留指定键、或者构造统计结果的键)时无法正常工作。
我知道可以用path/1解决,但会大幅增加代码复杂度;另一种方法是在函数开头复制字段成新键,结尾再删除,但既低效又不易读。想找更简洁、可读性更强的实现方式。
更新内容
- 示例输入:
[ {"type":1, "name": "foo"}, {"type":1, "name": "bar"}, {"type":2, "name": "joe"} ]
- 期望调用及结果:
调用.[ ] | keep_field_only(.type),输出:
{"type": 1} {"type": 1} {"type": 2}
调用count_by(.type),输出:
[ {"type":1, "count": 2}, {"type":2, "count": 1} ]
解决方案
在jq中,实现动态键名的对象构造,核心是利用[(key)]: value语法——把动态的键用括号包裹,jq就会将其解析为键名而非字符串字面量,这是最简洁直观的解决方式。
改进后的keep_field_only函数
def keep_field_only(field): { (field): .[field] } ;
这里(field)会被解析为传入的字段名(比如.type对应的"type"),再取当前对象中该字段的值,最终构造出仅包含目标键值对的对象。
改进后的count_by函数
def count_by(field): group_by(field) | map( { (field): .[0][field], count: length } ) ;
同样用(field)作为动态键名,. [0][field]取分组后第一个元素的对应字段值(分组内所有元素的该字段值一致),结合length统计分组长度,生成符合预期的统计结果。
验证调用
用示例输入测试:
- 保留指定字段:
jq '.[ ] | keep_field_only(.type)' input.json
输出与预期完全一致。
- 按字段统计:
jq 'count_by(.type)' input.json
输出符合预期。
这种方式无需额外的字段复制或path操作,代码简洁直观,可读性强。
内容的提问来源于stack exchange,提问作者wass rubleff
相关产品推荐
相关产品推荐

