1

I am new to jq and stuck with this problem for a while. Any help is appreciable.

I have two json files,

In file1.json:

{
    "version": 4,
    "group1": [
        {
            "name":"olditem1",
            "content": "old content"
        }
    ],
    "group2": [
        {
            "name":"olditem2"
        }
    ]
}

And in file2.json:

{
    "group1": [
        {
            "name" : "newitem1"
        },
        {
            "name":"olditem1",
            "content": "new content"
        }
    ],
    "group2": [
        {
            "name" : "newitem2"
        }
    ]
}

Expected result is:

{
    "version": 4,
    "group1": [
        {
            "name":"olditem1",
            "content": "old content"
        },
        {
            "name" : "newitem1"
        }
    ],
    "group2": [
        {
            "name":"olditem2"
        },
        {
            "name" : "newitem2"
        }
    ]
}

Criterial for merge:

  1. Has to merge only group1 and group2
  2. Match only by name

I have tried

jq -S '.group1+=.group1|.group1|unique_by(.name)' file1.json file2.json

but this is filtering group1 and all other info are lost.

2
  • On a match, should the elements in file1.json be updated (i.e. overwritten) by those from file2.json, or is it the other was round? Merging algorithms tend to follow the former ordering, but your expected output suggests the latter. (From the items in .group1 with name olditem1, the expected output features the one from file1.json, not the one from file2.json.) Commented Apr 8, 2022 at 9:04
  • Yes, file1 objects should take precedence. Commented Apr 8, 2022 at 10:14

1 Answer 1

2

This approach uses INDEX to create a dictionary of unique elements based on their .name field, reduce to iterate over the group fields to be considered, and an initial state created by combining the slurped (-s) input files using add after removing the group fileds to be processed separately using del.

jq -s '
  [ "group1", "group2" ] as $gs | . as $in | reduce $gs[] as $g (
    map(del(.[$gs[]])) | add; .[$g] = [INDEX($in[][$g][]; .name)[]]
  )
' file1.json file2.json
{
  "version": 4,
  "group1": [
    {
      "name": "olditem1",
      "content": "new content"
    },
    {
      "name": "newitem1"
    }
  ],
  "group2": [
    {
      "name": "olditem2"
    },
    {
      "name": "newitem2"
    }
  ]
}

Demo

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.