7

I am trying to build a single JSONPath query which will test existence of two or more paths.

Let's consider the following sample document:

{
          "firstName": "John",
          "lastName" : "doe",
          "age"      : 26,
          "address"  : {
            "streetAddress": "naist street",
            "city"         : "Nara",
            "postalCode"   : "630-0192"
          },
          "phoneNumbers": [
            {
              "type"  : "iPhone",
              "number": "0123-4567-8888"
            },
            {
              "type"  : "home",
              "number": "0123-4567-8910"
            }
          ]
}

So far I have found:

$..[firstName,lastName,type]

And get all of these elements from the entire document.

But, what I need is to check two different paths, e.g.:

 $.firstName 
 $.address.city

Can this be done with a single JSONPath query? I cannot write anything like:

$.[firstName,address.city]

With XML and XPath I could write:

/person/firstname | /person/address/city

and get a union of all matching XML elements.

Can I do the same with JSONPath?

KarelHusa
  • 1,995
  • 18
  • 26

2 Answers2

6

I think the closest you can come in the original JSONPath is using recursive descent and union, i.e.

$..['firstName','city']

The Goessner implementation will return

[
   "John",
   "Nara"
]

kubernetes JSONPath supports an extension to the union operator, allowing

[‘metadata.name’, ‘status.capacity’]

where name and capacity are members of metadata and status.

JSONMatch, which is a variant of JSONPath, and originally based on the Kubernetes JSONPath parser, supports union of completely separate paths, e.g.

[employee[5].name, company.name, wageTiers[compensation > 10000]]

JSONMatch is available in go and I believe javascript also.

A handful of JSONPath implementations support bracket notation with two literals separated by dot and bracket notation with two literals separated by dot without quotes.

The jsoncons C++ library (since 0.161.0) supports JSONPath union of completely separate paths with the notation

$..['firstName',@.address.city]
Daniel
  • 728
  • 7
  • 11
  • Yes, I have also come to this point, but I wonder if distinct paths can be queried by a single query. – KarelHusa Apr 04 '19 at 08:27
  • 1
    As the author of a [C++ JsonPath implementation](https://goessner.net/articles/JsonPath/), I would say the answer is no, with a strict interpretation of the [spec](https://goessner.net/articles/JsonPath/), to the extent that it can be called a "spec". The question has come up before, and it may be possible to imagine an extension. But I don't know of any existing implementations that has one. – Daniel Apr 08 '19 at 19:24
  • Thanks, so, this might be an answer to my question. – KarelHusa Apr 09 '19 at 12:59
0

This answer is not 100% an answer to the question as it assumes nodejs/javascript. Since it describes how we overcame the limitations of JSONPath it is my hope that it might help others.


We had a similar requirement. However we needed to look for hundreds of different paths and do processing for them and performance was an actual issue. We then replaced JSONPath with object-scan. It's a bit more limited, but has some advantages when you need to do data processing.

Here is how you could solve your question (note that you could separate the compile and run part to make subsequent executions more performant):

// const objectScan = require('object-scan');

const data = { firstName: 'John', lastName: 'doe', age: 26, address: { streetAddress: 'naist street', city: 'Nara', postalCode: '630-0192' }, phoneNumbers: [{ type: 'iPhone', number: '0123-4567-8888' }, { type: 'home', number: '0123-4567-8910' }] };

const r = objectScan(['firstName', 'address.city'], { rtn: 'count' })(data);

console.log(r);
// => 2
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

Disclaimer: I'm the author of object-scan

vincent
  • 1,953
  • 3
  • 18
  • 24