У меня есть массив json из сотен объектов, и каждый объект содержит (среди многих других полей) два таких массива и индикатор состояния:
"searchMetaData": {"rrStandard": ["XYZ5.1","6.3"],"ccStandard": ["46d45a68-a930","8cd1dc9a-d6a2"],"status": "complete"}
Для любого объекта со статусом «завершен» я хочу просмотреть массив rrStandard и удалить все элементы массива, которые не начинаются с XYZ (т. е. будет удалено «6.3»). Но мне также нужно удалить соответствующий элемент в массиве ccStandard, но в этом массиве нет шаблонов, по которым я мог бы сопоставить, поэтому я думаю, что мне придется удалить на основе соответствующего индексного номера.
Есть ли способ с помощью jq удалить «6.3» из rrStandard, каким-то образом запомнить, каким был его индекс (например, 1), а затем удалить элемент с тем же индексом (например, индекс 1) в массиве ccStandard?
В производственном случае эти массивы иногда будут иметь более двух значений в массивах, но количество элементов в них будет совпадать. Итак, возможно, мне нужно удалить элементы 1,2 и 3, например, в обоих массивах.
Я новичок в jq и (я думаю) понял, как найти и удалить «6.3» из rrStandard, но оттуда я заблудился.
Вот что мне удалось просто найти и удалить «6.3» из rrStandard:
.[].searchMetaData |= if (.status == "complete") then (del(.rrStandard[] | select(startswith("XYZ") | not))) else . end
Один из способов — использовать to_entries
для получения массива индексов и значений, фильтрации значений и использования индексов для удаления из обоих массивов. В качестве альтернативы, как предлагает @oguz, используйте path
для получения индексов:
del(.[].searchMetaData | select(.status == "complete") | (
.rrStandard, .ccStandard
)[
.rrStandard | to_entries[] | select(.value | startswith("XYZ") | not).key
# or: .rrStandard | path(.[] | select(startswith("XYZ") | not))[]
])
Другой способ — переместить reduce
над keys
в одном массиве и удалить из обоих массивов, если есть совпадение. Итерация сделана для того, чтобы reverse
не затрагивала более высокие индексы после удаления более низких:
(.[].searchMetaData | select(.status == "complete")) |= reduce (
.rrStandard | keys | reverse[]
) as $i (.;
del((.rrStandard, .ccStandard)[
select(.rrStandard[$i] | startswith("XYZ") | not) | $i
])
)
Еще один способ — скоординировать оба массива и transpose
их дважды. После первого элементы выстраиваются в ряд, и совпадающие можно удалить за один раз:
(.[].searchMetaData | select(.status == "complete")) |= . + (
[.rrStandard, .ccStandard]
| transpose | map(select(first | startswith("XYZ")))
| transpose | {rrStandard: first, ccStandard: last}
)
Вы ищете что-то вроде этого:
(.[].searchMetaData | select(.status == "complete")) |=
[.rrStandard | path (.[] | select(startswith("XYZ") | not))] as $p
| (.rrStandard, .ccStandard) |= delpaths($p)
@Рогелио, я не думаю, что это как-то связано с jq
Да, я думаю, ты прав. Я пытался расшифровать это. Похоже, что после текста и перед символом закрывающего массива "]" есть символ CR/LF, который не удаляется, и этот CR/LF не удаляется. Я являюсь посредником между поставщиком моего поставщика json и другим поставщиком, которому я отправляю json, но углублюсь в это.
@Rogelio Удачи, хорошего дня.
Спасибо. Кажется, это работает. Я заметил, что когда я просматриваю его в своем текстовом редакторе, он оставляет пустую строку в массиве, где удаленный элемент массива раньше находился в обоих массивах.