[英]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.