Làm cách nào để hợp nhất 2 đối tượng JSON từ 2 tệp bằng jq?


123

Tôi đang sử dụng jq công cụ (jq-json-processor) trong tập lệnh shell để phân tích cú pháp json.

Tôi có 2 tệp json và muốn hợp nhất chúng thành một tệp duy nhất

Đây là nội dung của các tệp:

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
        }
    }
}

kết quả mong đợi

{
    "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
        }
    }
}

Tôi thử rất nhiều tổ hợp nhưng kết quả duy nhất tôi nhận được là như sau, không phải là kết quả mong đợi:

{
  "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"
  }
}

Sử dụng lệnh này:

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

1
Bạn đã thử jsontool chưa? github.com/trentm/json
Nano Taboada

Vẫn chưa, tôi sẽ xem qua. Thx
Janfy

Để làm điều này với json sử dụng:cat f1 f2 | json --deep-merge
xer0x

bạn lấy ở đâu / bằng cách nào json @ xer0x?
Gus

@ Chúa ơi, để tải jsoncông cụ này, hãy truy cập github.com/trentm/json
xer0x

Câu trả lời:


154

Kể từ 1.4, điều này hiện có thể thực hiện được với *nhà điều hành. Khi cho hai đối tượng, nó sẽ hợp nhất chúng một cách đệ quy. Ví dụ,

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

Quan trọng: Lưu ý -s (--slurp)cờ đặt các tệp trong cùng một mảng.

Sẽ giúp bạn:

{
  "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
}

Nếu bạn cũng muốn loại bỏ các khóa khác (như kết quả mong đợi của bạn), một cách để làm điều đó là:

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

Hoặc có lẽ hơi hiệu quả hơn (vì nó không hợp nhất bất kỳ giá trị nào khác):

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

2
LƯU Ý : -scờ quan trọng vì nếu không có nó thì hai đối tượng không nằm trong một mảng.
John Morales

1
@SimoKinnunen Ở đây chúng tôi đang hợp nhất hai tệp json. Có thể có 1 biến json và tệp json khác không. Tôi đã thử nhưng nó có vẻ không hiệu quả với tôi!
Jayesh Dhandha

Nếu các tệp riêng lẻ được sắp xếp theo một khóa, liệu có thể giữ nguyên thứ tự trong tệp kết quả không?
Leo

@SimoKinnunen Tôi đang sử dụng lệnh này: "jq -s 'add' config.json other / *. Json" nhưng khi tôi thực hiện "cat config.json" thì nó không được hợp nhất. Làm cách nào để đưa đầu ra trở lại tệp?
Renato Bibiano

63

Sử dụng jq -s add:

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

Điều này đọc tất cả các văn bản JSON từ stdin vào một mảng (jq -s thực hiện điều đó) sau đó nó "giảm" chúng.

( addđược định nghĩa là def add: reduce .[] as $x (null; . + $x);, sẽ lặp lại các giá trị của mảng / đối tượng đầu vào và thêm chúng. Phép cộng đối tượng == hợp nhất.)


4
Có thể thực hiện hợp nhất đệ quy (toán tử *) với cách tiếp cận này không?
Dave Foster

1
@DaveFoster Có, với một cái gì đó như reduce .[] as $x ({}; . * $x)- xem thêm câu trả lời của jrib .
Chriki

Điều này đã giúp tôi hợp nhất hai tệp json bằng Ansible và jq. Cảm ơn.
Felipe Alvarez

35

Ai biết nếu bạn vẫn cần nó, nhưng đây là giải pháp.

Khi bạn đến --slurptùy chọn, thật dễ dàng!

--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.

Sau đó, +nhà điều hành sẽ làm những gì bạn muốn:

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

(Lưu ý: nếu bạn muốn hợp nhất các đối tượng bên trong thay vì chỉ ghi đè các đối tượng tệp bên trái với tệp bên phải, bạn sẽ cần phải thực hiện thủ công)


19

Đây là phiên bản hoạt động đệ quy (sử dụng *) trên một số đối tượng tùy ý:

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

2
Câu trả lời chính xác. Hoạt động tốt khi hợp nhất tất cả các tệp trong một thư mục:jq -s 'reduce .[] as $item ({}; . * $item)' *.json
John Ellmore

7

Đầu tiên, {"value": .value} có thể được viết tắt thành {value}.

Thứ hai, tùy chọn --argfile (có sẵn trong jq 1.4 và jq 1.5) có thể được quan tâm vì nó tránh phải sử dụng tùy chọn --slurp.

Đặt chúng lại với nhau, hai đối tượng trong hai tệp có thể được kết hợp theo cách cụ thể như sau:

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

Cờ '-n' cho biết jq không đọc từ stdin, vì các đầu vào đến từ các tùy chọn --argfile ở đây.


2
JQ đã bị phản đối --argilecho--slurpfile
David Groomes

3

Điều này có thể được sử dụng để hợp nhất bất kỳ số lượng tệp nào được chỉ định trong lệnh:

jq -rs 'reduce .[] as $item ({}; . * $item)' file1.json file2.json file3.json ... file10.json

hoặc cái này cho bất kỳ số lượng tệp nào

jq -rs 'reduce .[] as $item ({}; . * $item)' ./*.json

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.