Как слить 2 json файл с помощью jq?

Я использую jq инструменты (jq-json-processor) в оболочке script для разбора json.

У меня есть 2 json файла и хотят объединить их в один уникальный файл

Здесь содержимое файлов:

file1

{
    "value1": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2"
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        }
    }
}

file2

{
    "status": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value3": "v3"
        },      
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}

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

{
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        },
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}

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

{
  "ccc": {
    "value2": "v2",
    "value1": "v1"
  },
  "bbb": {
    "value2": "v2",
    "value1": "v1"
  },
  "aaa": {
    "value2": "v2",
    "value1": "v1"
  }
}
{
  "ddd": {
    "value4": 4,
    "value3": "v3"
  },
  "bbb": {
    "value3": "v3"
  },
  "aaa": {
    "value4": 4,
    "value3": "v3"
  }
}

С помощью этой команды:

jq -s '.[].value' file1 file2

Ответ 1

Начиная с 1.4, теперь это возможно с оператором *. При задании двух объектов он будет регрессировать их. Например,

jq -s '.[0] * .[1]' file1 file2

Вы получите:

{
  "value1": 200,
  "timestamp": 1382461861,
  "value": {
    "aaa": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3",
      "value4": 4
    },
    "bbb": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3"
    },
    "ccc": {
      "value1": "v1",
      "value2": "v2"
    },
    "ddd": {
      "value3": "v3",
      "value4": 4
    }
  },
  "status": 200
}

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

jq -s '.[0] * .[1] | {value: .value}' file1 file2

Или, предположительно, несколько более эффективный (поскольку он не объединяет никаких других значений):

jq -s '.[0].value * .[1].value | {value: .}' file1 file2

Ответ 2

Используйте jq -s add:

$ echo '{"a":"foo","b":"bar"} {"c":"baz","a":0}' | jq -s add
{
  "a": 0,
  "b": "bar",
  "c": "baz"
}

Это считывает все тексты JSON из stdin в массив (jq -s делает это), затем он "уменьшает" их.

(add определяется как def add: reduce .[] as $x (null; . + $x);, который выполняет итерацию по значениям входного массива/объекта и добавляет их. Добавление объекта == merge.)

Ответ 3

Кто знает, если вам все еще нужно, но вот решение.

Как только вы перейдете к опции --slurp, это легко!

--slurp/-s:
    Instead of running the filter for each JSON object in the input,
    read the entire input stream into a large array and run the filter just once.

Затем оператор + сделает то, что вы хотите:

jq -s '.[0] + .[1]' config.json config-user.json

(Примечание: если вы хотите объединить внутренние объекты, а не просто переписать левый файл с нужными файлами, вам нужно будет сделать это вручную)

Ответ 4

Здесь версия, которая работает рекурсивно (используя *) на произвольном числе объектов:

echo '{"A": {"a": 1}}' '{"A": {"b": 2}}' '{"B": 3}' | jq --slurp 'reduce .[] as $item ({}; . * $item)'
{
  "A": {
    "a": 1,
    "b": 2
  },
  "B": 3
}

Ответ 5

Во-первых, { "значение":.value} может быть сокращено до просто значения {.}.

Во-вторых, может быть интересен параметр -argfile (доступен в jq 1.4 и jq 1.5), поскольку он избегает использования опции -slurp.

Объединяя их, два объекта в двух файлах могут быть объединены следующим образом:

$ jq --argfile o1 file1 --argfile o2 file2 '$o1 * $o2 | {value}'