0

This is a follow-up on jq select error: "Cannot index string with string <object>"

Previously, I can filter the entries in a json file that has the target objects with the following command and filter:

[{
    "input": {
        "obj1": {
            "$link": "randomtext1"
        },
        "id": "a"
    }
}]

jq -r '.[] | select( any(.input[]; type=="object" and has("$link") and (.["$link"]=="randomtext1")))|.id' will give "a"

How can I filter if now the key "$link" and its value "randomtext1" belong to an array?

[{
    "input": {
        "obj1": [{
            "$link": "randomtext1"
        }],
        "id": "a"
    }
}]

(I still want to be able to find "a" as the result)

Example .json:

[
  {
    "input": {
      "obj1": [{
        "$link": "randomtext1"
      }],
      "obj2": [{
        "$link": "randomtext2"
      }],
      "someotherobj": "123"
    },
    "id": "a"
  },
  {
    "input": {
      "obj3": {
        "$link": "randomtext1"
      },
      "obj4": {
        "$link": "randomtext2"
      }
    },
    "id": "b"
  }
]

I am hoping to find both a and b with "randomtext1" keyword but only got b with the same filter from the previous case after obj1 and obj2 have been "shielded/masked" by the array brackets in the example json file.

0

Simply add an "or" to cover the new possibility:

.[]
| select( any(.input[];
              (type=="object" and (has("$link") and (.["$link"]=="randomtext1")))
              or (type=="array" and any(.[];
                                        type =="object" and (has("$link") and (.["$link"]=="randomtext1")))) ))
|.id

... or more readably:

def relevant($txt):
  type =="object" and has("$link") and (.["$link"]==$txt);

.[]
| select( any(.input[];
              relevant("randomtext1")
              or (type=="array" and any(.[]; relevant("randomtext1"))) ))
|.id
  • Thanks! All these filter syntax is forming a big ball of spaghetti in my brain nicely. At least I have a template for the similar logic I try to do and for that I am grateful. – Mr Janitor Apr 18 at 17:44
0

as an alternative you may consider using a walk-path based unix utility jtc:

bash $ <file.json jtc -w'<id>l:<val>v[-1]<input>l[$link]:<randomtext1>' -T'{{val}}'
"a"
"b"
bash $ 

to elaborate on the walk-path (-w):

- '<id>l:< - will find each value labeled id

- <val>v will memorize the value into the namespace val

- [-1] step up one level off found entry (basically address a parent)

- <input>l[$link]:<randomtext1> - will find under given Json entry each record "$link": "randomtext1" under record "input"

if all successful, then interpolation occurs in (-T) and previously memorized value interpolated.

the same query will work with your input in your prior post as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.