Объединить 2 объекта JSON с помощью jq

#json #bash #merge #key #jq

#json #bash #объединить #Клавиша #jq

Вопрос:

У меня есть 2 объекта json в 2 переменных V1 и V2.

V1 — это

 {
  "Parameters: {
     "a": "value-of-a",
     "b": "value-of-b"
  }
}
  

V2 — это

 {
  "Parameters": {
     "a": "new-value-of-a",
     "c": "value-of-c"
  }
}
  

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

Ожидаемый

 {
   "Parameters": {
      "a": "new-value-of-a",
      "b": "value-of-b"
   }
}
  

Я попробовал следующее:

 (
echo '{ "Parameters": { "a": "value-of-a", "b": "value-of-b" } }'
'{ "Parameters": { "a": "new-value-of-a", "c": "value-of-c" } }'
| jq --slurp 'reduce .[] as $item ({}; . * $item)'
)

  

но это генерирует

Актуально

 {
   "Parameters": {
      "a": "new-value-of-a",
      "b": "value-of-b",
      "c": "value-of-c"
   }
}
  

Проблема в том, что я не хочу, чтобы в результате отображались узлы в версии V2, которых нет в версии V1. Кто-нибудь может мне помочь?

Ответ №1:

Вот решение без сокращения, которое концептуально просто и хорошо масштабируется:

 jq -n '
   # Emit the object with key-value pairs of $o2 
   # for keys that appear in both . and $o2
   def commonKeys($o2):
     keys_unsorted as $k1
     | ($o2|keys_unsorted) as $k2
     | [($k1 - ($k1-$k2))[] | {(.): $o2[.]}] | add
   ;
   input.Parameters as $dict
   | input
   | .Parameters |= (.   commonKeys($dict))

' v2.json v1.json 
  

Ответ №2:

Если $.Parameter объект прост, как в вашем примере

 jq 
 --argjson a '{ "Parameters": { "a": "value-of-a", "b": "value-of-b" } }' 
 --argjson b '{ "Parameters": { "a": "new-value-of-a", "c": "value-of-c" } }' 
 -n '
   $a | .Parameters | keys_unsorted as $whitelist 
 | $b | .Parameters | with_entries( select(.key | IN($whitelist[])) ) as $update
 | $a | .Parameters  = $update '

  

Если у вас есть два файла, вы могли бы (например) использовать input twice вместо --argjson .

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

1. Андрей, большое спасибо, что нашли время ответить на мой вопрос! Ценю это! Я был так далеко… Я вижу, что со статическими значениями это работает. Однако, как только я переключаюсь на —slurpfile, я получаю следующую ошибку: невозможно индексировать массив с помощью строки «Параметры» . Как это следует изменить, чтобы использовать —slurpfile ?

2. Я просто изменил сценарий, чтобы использовать —argfile вместо —slurpfile, и он работал просто отлично. Андрей, еще раз спасибо за вашу помощь! Ты спас мой день!

Ответ №3:

Вот простое и эффективное решение:

 jq -n '
   input.Parameters as $dict
   | input
   | .Parameters |= reduce keys_unsorted[] as $k (.;
       if ($dict|has($k)) then .[$k] = $dict[$k] else . end)
' v2.json v1.json 
  

Если два значения являются переменными оболочки, вы можете использовать --argjson или просто повторить их:

 echo "$v2" "$v1" | jq -n '...'
  

Существуют и другие способы предоставления двух значений, но в целом лучше избегать параметра командной строки -s.

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

1. input пытается прочитать одно значение JSON без какого-либо возврата. См. Руководство по jq stedolan.github.io/jq/manual