0

My JSON (simplified) looks like this:

[
    {"name" : "foobar",
      "id" : 123
    },
    {"name" : "bar",
      "id" : 123
    },
    {"name" : "foobar",
      "id" : 456
    }, ...
]

I'm using https://jsonpath.herokuapp.com/ to try and find the right JSONPATH syntax to filter out anything not starting with foo, and having id == 123.

Getting it to filter the ones that do start with foo is easy:

$..[?(@.name =~ /foo.*/i)]

This yields the following results:

[
   {
      "name" : "foobar",
      "id" : 123
   },
   {
      "name" : "foobar",
      "id" : 456
   }
]

I can get rid of the id 456 by adding an additional filter like so:

$..[?(@.name =~ /foo.*/i && @.id==123)]

But how do I do the opposite of getting the name starting with foo? I want all entities that do not start with foo.

I tried something like this:

$..[?(!@.name =~ /foo.*/i && @.id==123)]

Which at least parses as valid JSONPATH, and should negate the filter, but for some reason it still happily only reports the foobar entry:

[
   {
      "name" : "foobar",
      "id" : 123
   }
]

How can I achieve a NOT LIKE in JSONPATH?

Thanks!

SchmitzIT
  • 9,227
  • 9
  • 65
  • 92

3 Answers3

1

Regex to identify data not starting with a given string foo:

^([^f]|f[^o]|fo[^o])

If your regex engine supports negative lookahead, that reduces to

^(?!foo)

Note the starting anchor (^) that limits the permissible matching location to the start of the test string.

collapsar
  • 17,010
  • 4
  • 35
  • 61
1

Your attempt $..[?(!@.name =~ /foo.*/i && @.id==123)] is almost correct. Surround the regex condition with parenthesis before negating with ! like so $..[?(!(@.name =~ /foo.*/i) && @.id==123)]. Tested at https://jsonpath.herokuapp.com/

Edit: This was assuming that you were using Jayway's jsonpath (Java, https://github.com/json-path/JsonPath), but from the documentation link you provided for SmartBear, it looks like it uses the Goessner jsonpath (Javascript, https://goessner.net/articles/JsonPath/). Both, for whatever reason use slightly differing syntaxes.

riyasvaliya
  • 745
  • 6
  • 8
0

Thanks to @collapsar for nudging me in the correct direction, in that the key to solving it was in the regular expression (but specifically using the JavaScript Regular Expression syntax, and merging that with the JSONPath syntax).

What actually ended up doing the trick was reading the documentation for JASONPath a bit more careful. It states:

=~
Match a JavaScript regular expression. For example, [?(@.description =~ /cat.*/i)] matches items whose description starts with cat (case-insensitive).

Note: Not supported at locations that use Ready! API 1.1.

The link to Javascript Regular Expression in turn contains the following:

[^xyz]
A negated or complemented character set. That is, it matches anything that is not enclosed in the brackets. You can specify a range of characters by using a hyphen. Everything that works in the normal character set also works here.

For example, [^abc] is the same as [^a-c]. They initially match 'r' in "brisket" and 'h' in "chop."

The resulting expression that works is:

$..[?(@.name =~ /[^foo].*/ && @.id == 123)]

Result:

[
   {
      "name" : "bar",
      "id" : 123
   }
]

(I added an additional bar with id 456 to the JSON payload I had, to double-check the filter also worked).

SchmitzIT
  • 9,227
  • 9
  • 65
  • 92
  • Your solution only works by accident: What your pattern `[?(@.name =~ /[^foo].*/` does is filtering names that do neither start with `f` nor `o` - so `omg` would be filtered as well as `fab`, which most certainly is not what you want even if it works with your data at hand. Independent of this, the documentation you cite is at least misleading in claiming that `=~` matching follows JS regular expression syntax while concealing that the patterns are automatically augmented with start and end anchors (`^`, `$`). – collapsar Jul 23 '19 at 13:51
  • @collapsar - I tried exactly that, but that doesn't work. Contrary to intuition, for some reason the =~ won't allow itself to be negated :( – SchmitzIT Jul 23 '19 at 15:17
  • 1
    Ok, so I'll delete my previous comment. Thanks for the feedback. – collapsar Jul 23 '19 at 15:38