Добавить значение ключа к родительскому подэлементу, если дочерний элемент имеет определенное значение ключа

#json #parent-child #jq

#json #родитель-потомок #jq

Вопрос:

Я пытаюсь понять, каков наилучший способ добавить элемент json к родительскому элементу дочернего элемента, если этот дочерний элемент содержит определенный ключ: значение, и, наконец, распечатать весь json с помощью jq, который я пытаюсь лучше объяснить на примере. Входной json является:

 {
  "family": {
    "surname": "Smith"
  },
  "components": [
    {
      "name": "John",
      "details": {
        "hair": "brown",
        "eyes": "brown",
        "age": "56"
      },
      "role": "father"
    },
    {
      "name": "Mary",
      "details": {
        "hair": "blonde",
        "eyes": "green",
        "age": "45"
      },
      "role": "mother"
    },
    {
      "name": "George",
      "details": {
        "hair": "blonde",
        "eyes": "brown",
        "age": "25"
      },
      "role": "child"
    }
  ]
}
  

Я хочу добавить:
«описание»: «на 5 лет меньше 30»
на том же уровне «сведений», если «возраст» равен «25», а затем распечатайте результат:

 {
  "family": {
    "surname": "Smith"
  },
  "components": [
    {
      "name": "John",
      "details": {
        "hair": "brown",
        "eyes": "brown",
        "age": "56"
      },
      "role": "father"
    },
    {
      "name": "Mary",
      "details": {
        "hair": "blonde",
        "eyes": "green",
        "age": "45"
      },
      "role": "mother"
    },
    {
      "name": "George",
      "details": {
        "hair": "blonde",
        "eyes": "brown",
        "age": "25"
      },
      "role": "child",
      "description": "5 years less than 30"
    }
  ]
}
  

Единственным решением, которое я нашел, было применить обновление, но напечатать только содержимое «компонентов»;
затем я удалил из JSON и, наконец, вставил измененное содержимое «компонентов», ранее сохраненное таким образом:

 cat sample.json | jq -c ' .components[] | select(.details.age=="25") |= .   {description: "5 years less than 30" } ' > /tmp/saved-components.tmp
cat sample.json | jq --slurpfile savedcomponents /tmp/saved-components.tmp 'del(.components) | .   { components: [ $savedcomponents ] }'
  

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

Чем вы

Марко

Ответ №1:

Вы можете выбрать объект, соответствующий условию, и добавить к этому объекту. Что-то вроде приведенного ниже. Ключ в том, чтобы использовать = назначение модификации, чтобы не потерять другие объекты

 (.components[] | select(.details.age == "25"))  = { "description": "5 years less than 30" }
  

jqplay — Демо

Комментарии:

1. Спасибо, ваши решения и @peak работают очень хорошо; Я бы хотел установить для обоих значение accepted solution, но я не знаю, как это сделать. Я попытался повторить ваше решение следующим образом: cat sample.json | jq '(.components[] | select(.details.age == "25")) = { "description": "5 years less than 30" }' | jq '(.components[] | select(.details.age == "25")) = { "description": "under 30" }' и я ожидал увидеть два ключа описания, но я вижу только последнее обновление. Это функция jq, которая не допускает дублирования ключей, или операция » =»?

2. jq позволяет указывать повторяющиеся ключи, но обычно игнорирует все, кроме последнего. («Обычно», потому что это неверно, когда действует «потоковый анализатор» (включен с помощью —stream).)

Ответ №2:

Вот простое («без волшебства») и эффективное решение:

 .components |= 
  map(if .details.age=="25" then .description = "5 years less than 30" else . end)