(很难想出一个总结问题的标题,所以请随意改进它)。
我有一个包含以下内容的 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[]
中的每个项目都有一个 new property_A 的值(在 newProperties 列表下)生成具有相应 id 的输出, old 和 new(请参阅下面的所需输出)字段,而不管该属性在 oldProperties 列表中的值。此外,如果 oldProperties 中不存在 property_A,我仍然需要在 old 字段中填充一个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]"
}
注意:即使 property_A 不存在于 oldProperties 列表中,其他属性可能(和将) 存在。
我面临的问题是,当 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 情况,而我还需要其他情况。
有什么方法可以使用这个工具来实现吗?
提前致谢。
最佳答案
您的属性列表似乎是某个对象的值。您可以将它们映射到一个对象中,然后比较这些对象,然后报告结果。
你可以这样做:
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关于如何做到这一点。
关于json - 使用 jq 解析两个列表中存在的键(即使其中一个列表中可能不存在),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46671563/