Вопрос или проблема
У меня есть большой объект 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. Этот подход минимизирует риск ошибок и повышает читаемость вашего кода, что особенно важно при работе с большими и сложными структурами.