[英]jq 1.5 match a record where 2 or more keys match names and values
不太确定如何清楚地提出问题,但是,给出如下递归结构。 我将如何使用walk
将 2 个或多个键字符串与值匹配。 我不知道结果会在结构中的哪个位置。 它可能是顶级或 10 级深。
"children": {
"ccc": [{
"id": "ddd",
"des": "object d",
"parent": "ccc",
"other": "zzz"
},{
"id": "zzz",
"des": "object z",
"parent": "ccc",
"other" : "ddd"
}]
}
我想找到一个记录,其中key=id=ddd
&& key=parent=ccc
然后我想向该记录添加一个新的键/值。 使用.key|match("")
会给我一个匹配键的值而不是键名本身。 所以搜索ddd
可能匹配id
和other
。
我已经尝试了几种组合,如果在 bash 中进行,它看起来像
匹配标准
((.key|match("id") and (.key|test("ddd"))
and
((.key|match("parent") and (.key|test("ccc"))
新键值
+= {"newkey":"newValue"}
将匹配语句插入
walk(if type == "object"
then
with_entries(if ..match_criteria.. )
then ..new_key_value.. else . end)
所以结果应该是这样的
"children": {
"ccc": [{
"id": "ddd",
"des": "object d",
"parent": "ccc",
"other": "zzz",
"newkey": "newValue"
},{
"id": "zzz",
"des": "object z",
"parent": "ccc",
"other":"ddd"
}]
}
根据反馈意见,从@peak答案UPDATE我已经更新如下代码
jsonOut=$(jq 'walk(when(type == "object";
with_entries(
when(any(.value[]; .id == "ddd");
.value[] += {"newkey": "newValue"}
))))' <<< ${jsonIn})
不幸的是,这仍然留下两个悬而未决的问题
a) 此代码将{"newkey": "newValue"}
到搜索条件为真的所有子级,即:添加到id:ddd
&& id:zzz
,而不仅仅是添加到id:ddd
记录
"children": {
"ccc": [{
"id": "ddd",
"des": "object d",
"parent": "ccc",
"other": "zzz",
"newkey": "newValue"
},{
"id": "zzz",
"des": "object z",
"parent": "ccc",
"other":"ddd",
"newkey": "newValue"
}]
}
b) 向any
子句添加多个部分标准。 我曾尝试使用AND
或|
加入方法,但这会引发错误。
when(any(.value[]; .id == "ddd" | .other == "zzz"); //no match, no value added
or
when((any(.value[]; .id == "ddd") AND (any(.value[]; .other == "zzz"));
//error : unexpected ')', expecting $end
or
when(any(.value[]; .id == "ddd", .other == "zzz"); //no match, no value added
你能建议这两个问题的语法吗?
UPDATE2更好地理解when
过滤器,我现在已经嵌套了这些,它似乎可以缩小结果集。 但是问题a)
在匹配为真时更新两条记录仍然存在。
jsonOut=$(jq 'walk(when(type == "object";
with_entries(
when(any(.value[]; .id == "ddd");
when(any(.value[]; .other == "zzz");
.value[] += {"newkey": "newValue"}
)))))' <<< ${jsonIn})
输入
{"children": {
"ccc": [{
"id": "ddd",
"des": "object d",
"parent": "ccc",
"other": "zzz"
},{
"id": "zzz",
"des": "object z",
"parent": "ccc",
"other":"ddd"
}],
"www": [{
"id": "ddd",
"des": "object d",
"parent": "www",
"other": "ppp"
},{
"id": "kkk",
"des": "object z",
"parent": "www",
"other":"ddd"
}]
}}
输出
{
"children": {
"ccc": [{
"id": "ddd",
"des": "object d",
"parent": "ccc",
"other": "zzz",
"newkey": "newValue"
}, {
"id": "zzz",
"des": "object z",
"parent": "ccc",
"other": "ddd",
"newkey": "newValue" <=need to NOT add this entry
}],
"www": [{
"id": "ddd",
"des": "object d",
"parent": "www",
"other": "ppp"
}, {
"id": "kkk",
"des": "object z",
"parent": "www",
"other": "ddd"
}]
}
}
这是对“更新”问题的回答:
walk(when(type == "object";
with_entries(when(.key|test("ccc");
.value |= map( when(.id=="ddd";
. + {"newkey": "newValue"}))))))
将来,请遵循 mcve 指南: http ://stackoverflow.com/help/mcve
在这里使用walk
的最简单方法是将更新包含在if ... then ... else ...end
的“then”部分中。 为了强调和澄清这一点,并缩短了解决方案,我将使用通用的辅助功能, when
:
def when(filter; action): if (filter?) // null then action else . end;
现在可以用非常简单的方式编写问题的解决方案:
walk(when(type == "object";
with_entries(when(.key|test("ccc");
when(any(.value[]; .id == "ddd");
.value += ["ADDITIONAL"])))))
当然,您可能需要比 .id == "ddd" 更高级的测试,并且您可能希望每个 "ccc" 对象只执行一次更新,但将使用相同的结构。
实际上,您可能还想将上述表达式包装在def
以便更容易地对其进行参数化和维护。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.