(很难想出一个总结问题的标题,所以随时改进它。)
我有一个包含以下内容的JSON文件:
{
"Items": [
{
"ID": {
"S": "ID_Complete"
},
"oldProperties": {
"L": [
{
"S": "[property_A : value_A_old]"
},
{
"S": "[property_B : value_B_old]"
}
]
},
"newProperties": {
"L": [
{
"S": "[property_A : value_A_new]"
},
{
"S": "[property_B : value_B_new]"
}
]
}
},
{
"ID": {
"S": "ID_Incomplete"
},
"oldProperties": {
"L": [
{
"S": "[property_B : value_B_old]"
}
]
},
"newProperties": {
"L": [
{
"S": "[property_A : value_A_new]"
},
{
"S": "[property_B : value_B_new]"
}
]
}
}
]
}
我想使用jq
操纵数据,以便Items[]
中每个具有 新 值的项目 property_A (在 newProperties 列表下)生成一个输出,其中包含 id , old 和 new (请参阅下面的所需输出)字段,无论该属性在 oldProperties 列表中的值如何。此外,如果 oldProperties 中不存在 property_A ,我仍然需要填充旧字段null
(或任何固定的字符串,用于它的价值)。
期望的输出:
{
"id": "id_Complete",
"old": "[property_A : value_A_old]",
"new": "[property_A : value_A_new]"
}
{
"id": "ID_Incomplete",
"old": null,
"new": "[property_A : value_A_new]"
}
注意:即使 oldProperties 列表中不存在 property_A ,其他属性也可能(和将存在。
我面临的问题是,当 oldProperties 列表中不存在所需的属性时,我无法获得输出。我当前的jq
命令如下所示:
jq -r '.Items[] |
{ id:.ID.S,
old:.oldProperties.L[].S | select(. | contains("property_A")),
new:.newProperties.L[].S | select(. | contains("property_A")) }'
只渲染 ID_Complete 的情况,而我也需要另一个。
使用此工具有没有办法实现这一目标?
提前致谢。
答案 0 :(得分:2)
您的属性列表似乎是某个对象的值。您可以将它们映射到对象中,然后对对象进行差异,然后报告结果。
你可以这样做:
def make_object_from_properties:
[.L[].S | capture("\\[(?<key>\\w+) : (?<value>\\w+)\\]")]
| from_entries
;
def diff_objects($old; $new):
def _prop($key): select(has($key))[$key];
([($old | keys[]), ($new | keys[])] | unique) as $keys
| [ $keys[] as $k
| ({ value: $old | _prop($k) } // { none: true }) as $o
| ({ value: $new | _prop($k) } // { none: true }) as $n
| (if $o.none then "add"
elif $n.none then "remove"
elif $o.value != $n.value then "change"
else "same"
end) as $s
| { key: $k, status: $s, old: $o.value, new: $n.value }
]
;
def diff_properties:
(.oldProperties | make_object_from_properties) as $old
| (.newProperties | make_object_from_properties) as $new
| diff_objects($old; $new) as $diff
| foreach $diff[] as $d ({ id: .ID.S };
select($d.status != "same")
| .old = ((select(any("remove", "change"; . == $d.status)) | "[\($d.key) : \($d.old)]") // null)
| .new = ((select(any("add", "change"; . == $d.status)) | "[\($d.key) : \($d.new)]") // null)
)
;
[.Items[] | diff_properties]
这会产生以下输出:
[
{
"id": "ID_Complete",
"old": "[property_A : value_A_old]",
"new": "[property_A : value_A_new]"
},
{
"id": "ID_Complete",
"old": "[property_B : value_B_old]",
"new": "[property_B : value_B_new]"
},
{
"id": "ID_Incomplete",
"old": null,
"new": "[property_A : value_A_new]"
},
{
"id": "ID_Incomplete",
"old": "[property_B : value_B_old]",
"new": "[property_B : value_B_new]"
}
]
您的数据似乎也是某种编码格式。对于更强大的解决方案,您应该考虑定义一些函数来解码它们。考虑找到here的方法,了解如何做到这一点。
答案 1 :(得分:1)
此过滤器产生所需的输出。
def parse: capture("(?<key>\\w+)\\s*:\\s*(?<value>\\w+)") ;
def print: "[\(.key) : \(.value)]";
def norm: [.[][][] | parse | select(.key=="property_A") | print][0];
.Items
| map({id:.ID.S, old:.oldProperties|norm, new:.newProperties|norm})[]
示例运行(假定filter.jq
中的过滤器和data.json
中的数据)
$ jq -M -f filter.jq data.json
{
"id": "ID_Complete",
"old": "[property_A : value_A_old]",
"new": "[property_A : value_A_new]"
}
{
"id": "ID_Incomplete",
"old": null,
"new": "[property_A : value_A_new]"
}