0

I have similar question as how-to-use-jq-to-find-all-paths-to-a-certain-key and also checked the accepted answer.

The solution described in answer works for the exactly same input as the ticket, but after I updated the json a little bit as following (remove last foo part), I can't get any output by filter:

fromstream(tostream | select(.[0]|index("foo")))

The updated input json:

{
    "A": {
      "A1": {
        "foo": {
          "_": "_"
        }
      },
      "A2": {
        "_": "_"
      }
    },
    "B": {
      "B1": {}
    }
}

The expected output should be:

{
    "A": {
      "A1": {
        "foo": {
          "_": "_"
        }
      }
    }
}

But I got nothing. You can check here https://jqplay.org/s/s21FFUeoQz0.

I've also tried the filter without fromstream:

tostream | select(.[0]|index("foo"))

The output will be as following, it seems work here.

[["A","A1","foo","_"],"_"]
[["A","A1","foo","_"]]
[["A","A1","foo"]]

So I suspect the fromstream has some problem. Can anyone help me figure out? Thanks!

Bin He
  • 23
  • 4

3 Answers3

1
fromstream(tostream | select(length==1 or (.[0]|index("foo"))))

Depending on your requirements, you might be able to make things more efficient by wrapping the above expression in a call to first().

—-

FYPI, a less obscure approach would be along the lines of:

paths as $p
| select($p[-1]=="foo")
| getpath($p) as $v
| {} | setpath($p;$v)
peak
  • 105,803
  • 17
  • 152
  • 177
  • Cool! it works. Thank you very much for your so quick response. But I can't really understand the magic behind? By adding `length==1 or` will help select more items, even those items without "foo", though it will help `fromstream` to get right output? – Bin He Oct 20 '22 at 08:23
1

You're looking for something like this:

. as $in
| reduce (paths | select(.[-1] == "foo")) as $p (
    null;
    setpath($p; $in | getpath($p))
)

Online demo

oguz ismail
  • 1
  • 16
  • 47
  • 69
0

Who doesn't like obscure, inefficient solutions to problems?

delpaths(
    [paths|select(index("foo"))] as $foos
    | [paths|select(. as $p | $foos | map(index($p) != 0) | all)]
)

First build a list of all paths containing a "foo" object/property. Then filter all paths leading to these paths. Finally, delete them.

knittl
  • 246,190
  • 53
  • 318
  • 364