JQ получить ключ объекта и изменить его имя в одном фильтре - PullRequest
0 голосов
/ 11 апреля 2020

Я работаю с этим JSON (частью более крупного JSON кода):

group='{ "129": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 129 } }'

Сначала я получаю ключ верхнего уровня (здесь "129"), который на самом деле может быть любым числом:

key=`echo $group | jq 'keys[0]'` # "129"

Я хочу изменить этот ключ на другой номер с именем nextID, который я получил от другой записи в большем JSON:

nextID=`echo $groups_meta | jq '.nextID'` # 130

Сейчас здесь проблема. Я могу изменить ключ с помощью следующего фильтра, но мне кажется, что он довольно сложный:

new_group=`echo $group | jq --arg key $key --arg nextID $nextID 'with_entries( if .key | contains($key) then .key |= "$nextID" else . end)'`

Вы видите, что фильтр находит ключ, выполняя поиск для имени. Это может быть проблемой, если позже появится другой ключ с тем же именем. Это франк agile. И этот метод кажется довольно сложным; Мне бы очень хотелось получить ключ (как в keys[0] выше) и использовать его для изменения, все в одном и том же фильтре.

Так что мой вопрос: есть ли способ объединить обе части, и получить ключ без поиска?

ОБНОВЛЕНИЕ

Пример ввода:

group='{ "129": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 129 } }'
nextID=130

jq команда:

new_group=`echo $group | jq --arg nexID $nextID 'filter'`

Ожидаемый результат:

echo $new_group
{ "130": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 130 } }

Обратите внимание, что первая клавиша "129" должна указываться по позиции, аналогично keys[0], как показано выше, так как число заранее неизвестно. Значение ключа id также установлено на "130". Оба должны быть установлены с переменной bash $nextID, импортированной в jq.

ОБНОВЛЕНИЕ 2

Используя ответ @ jq170727, я добавил несколько изменений значения после nextID успешно, но есть проблема при изменении значения .title в том же вводе на строку с пробелами :

title="new title"
new_group=`echo $group | jq --arg nextID $nextID --arg title $title '(keys_unsorted|first) as $i | with_entries(if .key == $i then .key=$nextID | .value.id=$nextID | .value.title=$title else . end)'`

Это приводит к ошибке:

jq: error: title/0 is not defined at <top-level>, line 1:
title

Цитирование переменной заголовка в команде jq .value.title="$title" также приводит к ошибкам. Если в заголовке нет пробелов в bash, команда работает.

Я пропустил трюк для обновления значений с переменными, содержащими пробелы? Должен ли я задать новый вопрос?

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

Исправленный ответ

Ваш оригинальный фильтр был довольно близок. Вот тот, который делает то, что вы просили.

(keys_unsorted|first) as $i | with_entries(if .key == $i then .key=$nexID| .value.id=$nexID else . end)

Интерактивный пример в bash: Попробуйте онлайн!

Предыдущий ответ

Скорее кроме использования отдельных вызовов, вы можете выполнить всю операцию за один раз.
Например, предполагая, что ваш полный json похож на

{
  "group": {
    "129": {
      "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 },
      "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true,
      "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 129
    }
  },
  "groups_meta": {
    "nextID": 130
  }
}

Вы можете использовать этот фильтр

   (.group | keys_unsorted | first) as $i
 | (.groups_meta.nextID | tostring) as $n
 | .group |= with_entries( if .key == $i then .key = $n | .value.id = $n else . end ) 

Попробуйте онлайн!

Это означает, что строка, сгенерированная из nextID, отсутствует в group.
Если вы также хотите обновить nextID, вы можете добавить что-нибудь как | .groups_meta.nextID += 1 до конца.

0 голосов
/ 12 апреля 2020

Поскольку у объекта 'group' есть только один ключ верхнего уровня, нет необходимости предотвращать сортировку, поэтому пересмотренный фильтр @ jq170727 можно немного упростить:

with_entries(.key=$nextID | .value.id=$nextID)

Ответ на мой обновление 2:

Импортированная переменная bash должна быть заключена в кавычки. Чтобы избежать ошибок из-за пробелов в значении, имеет смысл заключить в кавычки все импортированные переменные:

new_group=`echo $group | jq --arg nextID "$nextID" --arg title "$title" 'with_entries(.key=$nextID | .value.id=$nextID | .value.title=$title)'`

Вывод:

{ "130": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "new title", "id": "130" } }
...