Обновить объект внутри массива внутри другого JSON-объекта

Вопрос или проблема

У меня есть большой объект JSON с массивом объектов внутри него. Мне нужно добавить пару ключ:значение к конкретному объекту в массиве. Например, пусть входной объект будет следующим:

{
  "a": {
    "b": [
      {
        "name": "name1",
        "value": 1,
        "param": {
          "p1": "par1"
        }
      },
      {
        "name": "name2",
        "value": 2,
        "param": {
          "p1": "par2"
        }
      },
      {
        "name": "name3",
        "value": 3,
        "param": {
          "p1": "par3"
        }
      }
    ],
    "c": 4,
    "d": 5
  }
}

Используя индекс, модификация проста:

 jq '.a.b[0].param += {new: "QQQ"}'

Но я не могу быть на 100% уверенным в индексе. Я должен указать объект с тегом имени .name == "name1".

Как модифицировать объект, идентифицированный по тегу имени?

Не знаю, как лучше это сделать, но вы можете сделать:

.a.b |= map(if .name == "name1" then (.new = "QQQ") else . end)

Кажется естественным выбирать элемент для обновления с помощью select(), а затем использовать map() для сопоставления выбора и присвоения всем элементам подмассива b:

jq '.a.b |= map(select(.name == "name1").param += { new: "QQQ" })'  file

или, короче

jq '.a.b |= map(select(.name == "name1").param.new = "QQQ")' file

Или, вы можете извлечь все записи param из элементов массива b и обновить их. Это будет ближе к вашей команде, которая безусловно обновляет первый элемент b:

jq '(.a.b[] | select(.name == "name1").param) += { new: "QQQ" }'

или, короче,

jq '(.a.b[] | select(.name == "name1").param).new = "QQQ"'  file

Ответ или решение

Чтобы обновить объект внутри массива внутри другого JSON-объекта, существует несколько способов, используя утилиту jq, которая является инструментом для обработки JSON в командной строке.

Пример JSON-объекта

Допустим, у вас есть следующий JSON-объект:

{
  "a": {
    "b": [
      {
        "name": "name1",
        "value": 1,
        "param": {
          "p1": "par1"
        }
      },
      {
        "name": "name2",
        "value": 2,
        "param": {
          "p1": "par2"
        }
      },
      {
        "name": "name3",
        "value": 3,
        "param": {
          "p1": "par3"
        }
      }
    ],
    "c": 4,
    "d": 5
  }
}

Задача

Вам необходимо добавить новый ключ-значение к объекту, идентифицируемому по значению ключа name, например, для name1 вы хотите добавить { new: "QQQ" } к его параметрам.

Решения с использованием jq

1. Использование map() с условием

Вы можете использовать функцию map, чтобы пройтись по всем элементам массива и выполнить проверку по значению name. В случае нахождения соответствующего имени, мы обновим param:

jq '.a.b |= map(if .name == "name1" then (.param += {new: "QQQ"}) else . end)'

Данный подход позволяет сохранить все элементы массива в оригинальном состоянии, за исключением того, у которого name совпадает с "name1".

2. Использование select()

Для более изящного решения вы можете использовать select(), чтобы выбрать нужный элемент массива и обновить его параметры:

jq '.a.b |= map(select(.name == "name1") | .param += {new: "QQQ"})'

Этот подход делает выбор более явным, добавляя новое поле к параметрам объекта только при выполнении условия.

3. Альтернативный вариант

Можно еще более кратко записать команду, осуществив тот же результат:

jq '.a.b[] | select(.name == "name1") | .param.new = "QQQ"'

В этом варианте происходит выбор нужного элемента с помощью select(), и моментально добавляем новое значение new.

Заключение

Эти методы предоставляют возможность гибко и эффективно изменять объекты в сложной структуре JSON, сохраняя при этом целостность данных. Использование jq позволяет выполнять преобразования без необходимости в написании дополнительного кода, что оптимизирует процесс работы с JSON. Этот подход минимизирует риск ошибок и повышает читаемость вашего кода, что особенно важно при работе с большими и сложными структурами.

Оцените материал
Добавить комментарий

Капча загружается...