1

My jq command returns objects in brackets but without comma separators. But I would like to create a new json string from it.

This call finds all elements of arr that have a FooItem in them and then returns texts from the nested array at index 3:

jq '.arr[] | select(index("FooItem")) | .[3].texts' 

on this json (The original has more elements ):

 {
      "arr": [
        [
          "create",
          "w199",
          "FooItem",
          {
            "index": 0,
            "texts": [
              "aBarfoo",
              "avalue"
            ]
          }
        ],
        [
          "create",
          "w200",
          "NoItem",
          {
            "index": 1,
            "val": 5,
            "hearts": 5
          }
        ],
        [
          "create",
          "w200",
          "FooItem",
          {
            "index": 1,
            "texts": [
              "mybarfoo",
              "bValue"
            ]
          }
        ]
    ]
    }

returns this output:

[
  "aBarfoo",
  "avalue"
]
[
  "mybarfoo",
  "bValue"
]

But I'd like to create a new json from these objects that looks like this:

{
    "arr": [
        [
            "aBarfoo",
            "avalue"
        ],
        [
            "mybarfoo",
            "bValue"
        ]
    ]
}

Can jq do this?

EDIT

One more addition: Considering that texts also has strings of zero length, how would you delete those/not have them in the result?

"texts": ["",
          "mybarfoo",
          "bValue",
          ""
          ]

1 Answer 1

2

You can always embed a stream of (zero or more) JSON entities within some other JSON structure by decorating the stream, that is, in the present case, by wrapping the STREAM as follows:

{ arr: [ STREAM ] }

In the present case, however, we can also take the view that we are simply editing the original document, and accordingly use a variation of the map(select(...)) idiom:

.arr |= map( select(index("FooItem")) | .[3].texts) 

This latter approach ensures that the context of the "arr" key is preserved.

Addendum

To filter out the empty strings, simply add another map(select(...)):

.arr |= map( select(index("FooItem"))
             | .[3].texts | map(select(length>0)))
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you! it works! However I will definitely have to wrap my head around it to understand it.
Is there a way to rename the array arr in the output ?
Of course. Using the first approach, you just specify the alternative name. Using the second approach, you could for example write: .newname = (.arr | map(...)) | del(.arr)
Thank you @peak. I had one more final addition, but did not want to ask it in the comments, so I made an edit to the question. Maybe you can help me out one more time.
Thanks for the addendum!!

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.