0

I have an array of JSON objects formatted as follows:

[
  {
    "id": 1,
    "names": [
      {
        "name": "Bulbasaur",
        "language": {
          "name": "en",
          "url": "http://myserver.com:8000/api/v2/language/9/"
        }
      },
    ],
  },
  {
    "id": 1,
    "types": [
      {
        "slot": 1,
        "type": {
          "name": "grass",
          "url": "http://myserver.com:8000/api/v2/type/12/"
        }
      },
      {
        "slot": 2,
        "type": {
          "name": "poison",
          "url": "http://myserver.com:8000/api/v2/type/4/"
        }
      }
    ]
  },
  {
    "id": 2,
    "names": [
      {
        "name": "Ivysaur",
        "language": {
          "name": "en",
          "url": "http://myserver.com:8000/api/v2/language/9/"
        }
      },
    ],
  },
  {
    "id": 2,
    "types": [
      {
        "slot": 1,
        "type": {
          "name": "ice",
          "url": "http://myserver.com:8000/api/v2/type/10/"
        }
      },
      {
        "slot": 2,
        "type": {
          "name": "electric",
          "url": "http://myserver.com:8000/api/v2/type/8/"
        }
      }
    ]
  },
  {
    "id": 3,
    "names": [
      {
        "name": "Venusaur",
        "language": {
          "name": "en",
          "url": "http://myserver.com:8000/api/v2/language/9/"
        }
      },
    ],
  },
  {
    "id": 3,
    "types": [
      {
        "slot": 1,
        "type": {
          "name": "ground",
          "url": "http://myserver.com:8000/api/v2/type/2/"
        }
      },
      {
        "slot": 2,
        "type": {
          "name": "rock",
          "url": "http://myserver.com:8000/api/v2/type/3/"
        }
      }
    ]
  }
]

Note that these are pairs of separate objects that appear sequentially in a JSON array, with each pair sharing an id field. This pattern repeats several hundred times in the array. What I need to accomplish is to "merge" each id-sharing pair into one object. So, the resultant output would be

[
  {
    "id": 1,
    "names": [
      {
        "name": "Bulbasaur",
        "language": {
          "name": "en",
          "url": "http://myserver.com:8000/api/v2/language/9/"
        }
      },
    ],
    "types": [
      {
        "slot": 1,
        "type": {
          "name": "grass",
          "url": "http://myserver.com:8000/api/v2/type/12/"
        }
      },
      {
        "slot": 2,
        "type": {
          "name": "poison",
          "url": "http://myserver.com:8000/api/v2/type/4/"
        }
      }
    ]
  },
  {
    "id": 2,
    "names": [
      {
        "name": "Ivysaur",
        "language": {
          "name": "en",
          "url": "http://myserver.com:8000/api/v2/language/9/"
        }
      },
    ],
    "types": [
      {
        "slot": 1,
        "type": {
          "name": "ice",
          "url": "http://myserver.com:8000/api/v2/type/10/"
        }
      },
      {
        "slot": 2,
        "type": {
          "name": "electric",
          "url": "http://myserver.com:8000/api/v2/type/8/"
        }
      }
    ]
  },
  {
    "id": 3,
    "names": [
      {
        "name": "Venusaur",
        "language": {
          "name": "en",
          "url": "http://myserver.com:8000/api/v2/language/9/"
        }
      },
    ],
    "types": [
      {
        "slot": 1,
        "type": {
          "name": "ground",
          "url": "http://myserver.com:8000/api/v2/type/2/"
        }
      },
      {
        "slot": 2,
        "type": {
          "name": "rock",
          "url": "http://myserver.com:8000/api/v2/type/3/"
        }
      }
    ]
  }
]

I've gotten these objects to appear next to each other via the group_by(.id) command, but I'm at a loss as to how I should actually combine them. I'm very much still a novice with jq so I'm a bit overwhelmed with the amount of possible solutions.

1
  • 2
    Show us a complete JSON to work with and not snippets. Commented Dec 3, 2019 at 6:17

1 Answer 1

2

[Note: The following assumes that the data shown in the Q have been corrected so that they are valid JSON.]

The merging you want can be achieved by object addition (x + y). For example, given the two JSON objects as shown in the question (i.e., as a stream), you could write:

jq -s '.[0] + .[1]'

However, since the question also indicates these objects are actually in an array, let's next consider the case of an array with two objects. In that case, you could simply write:

jq add

Finally, if you have an array of arrays each of which is an array of objects, you could use map(add). Since you don't have a very large array, you could simply write:

group_by(.id) | map(add)

Please note that jq defines object addition in a non-commutative way. Specifically, there is a bias towards the right-most key.

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

5 Comments

Thanks! The solution works but I need it to work on more than just two items (see the edit). So the output would be .[0] and .[1] merged together, followed by .[2] and .[3] merged together, and so on.
You mentioned you'd already used group_by so I assumed you could fill in the details. Anyway, I've included a simple solution using group_by.
I figured it out -- turns out that you have to do group_by(.id)[] (note the []) in order for the object pairs to actually be put in their own array. After that, it was as simple as piping to {} and choosing the fields I want from .[0] and .[1].
That gives you a stream, whereas your Q specified an array.
Apologies for the vagueness. I looked into the differences between the two and it would seem so. I'll accept your answer since it does answer the original question, which was just poorly formed due to a lack of understanding of jq.

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.