如何使用jq通过--arg传参为数组对象动态插入字段、替换嵌套对象为ID
解决方案
核心jq转换逻辑
你原命令的问题在于直接在根对象层级操作,没有遍历records数组的每个元素,导致字段加错层级,多元素场景下取值逻辑也会混乱。
以下是满足需求的正确jq命令:
# 测试用命令,直接输出格式化结果 jq --arg field "Account" --arg field_name_id "AccountID" ' .records[] |= ( if has($field) then .[$field_name_id] = .[$field].Id | del(.[$field]) else . end )' Contacts.json
逻辑说明:
- 用
|=对records数组的每一个元素做原地修改 - 先判断当前元素是否存在传入的
$field嵌套字段 - 存在则先新增
$field_name_id字段,取值为嵌套字段的Id属性,再删除原嵌套字段 - 不存在则保持原元素不变,不会报错
如果需要压缩输出适配你脚本里的临时文件逻辑,加上-c参数即可:
jq -c --arg field "$FIELD" --arg field_name_id "$FIELD_NAME_ID" ' .records[] |= ( if has($field) then .[$field_name_id] = .[$field].Id | del(.[$field]) else . end )' "$DATA_FILE" > "./$TEMP_FILE" 2> modify-json.errors
修正后的完整bash脚本
针对你原有脚本的小问题(比如变量未加引号、ls遍历文件名有空格会出错),优化后完整脚本如下:
#!/bin/bash # 入参为soql文件路径,用于调整sfdx:data:tree:export导出的JSON,适配导入格式要求 # 解决sfdx原生不支持2层以上深度关系查询导出导入的问题 if [ $# -ne 1 ]; then echo "用法: $0 <soql文件路径>" exit 1 fi SOQL_FILE="$1" # 提取所有选中了ID字段的关联对象名 FIELDS=$(grep -oe '\([A-Za-z_]\+\)\.[iI][dD]' "$SOQL_FILE" | cut -f 1 -d . | sort -u) # 遍历当前目录所有JSON文件 for DATA_FILE in *.json; do [ -f "$DATA_FILE" ] || continue # 脱敏邮箱地址 gsed -i 's/[^@ "]*@[^@]*\.[^@ ,"]*/fake@test.com/g' "$DATA_FILE" # 遍历所有需要替换的关联字段 for FIELD in $FIELDS; do if [[ $FIELD =~ __r ]]; then FIELD_NAME_ID="${FIELD/%__r/__c}" else FIELD_NAME_ID="${FIELD}ID" fi TEMP_FILE="temp-${DATA_FILE}.bk" echo "处理文件: $DATA_FILE, 字段: $FIELD -> $FIELD_NAME_ID" # 执行JSON转换 jq -c --arg field "$FIELD" --arg field_name_id "$FIELD_NAME_ID" ' .records[] |= ( if has($field) then .[$field_name_id] = .[$field].Id | del(.[$field]) else . end )' "$DATA_FILE" > "$TEMP_FILE" 2> modify-json.errors # 转换成功则覆盖原文件 if [ -s "$TEMP_FILE" ]; then jq '.' "$TEMP_FILE" > "$DATA_FILE" fi rm -f "$TEMP_FILE" done done
内容的提问来源于stack exchange,提问作者Manny Adumbire
相关产品推荐
相关产品推荐

