Search code examples
javajsonjsonpathjayway

JSON path condifitional index of element based on value of another field


I want to select array element based on value of another object(not array part)

{
  "array": [
    {
      "id": 1
    },
    {
      "id": 2
    }
  ],
  "conditionalField": "ab"
}

I want select array element based on value of $.conditionalField. I need something like this:

$.array[($.conditionalField == "ab" ? 0 : 1)]

Does json path support this? I use Jayway JSON Path


Solution

  • Unfortunately, this cannot be done in JSONPath as of now. Generally, current implementations lack the fluency of XPath 1.0 (let alone v2.0/3+).

    A (well known) trick mimicking a conditional (if-else) in a language like XPath 1.0 that does not come with such a feature is to use a technique called "Becker's method", i.e. concatenating two mutually exclusive strings, where one of two strings becomes empty depending on a condition. In (XPath) pseudo-code:

    concat(
      substring('foo', 1, number(true) * string-length('foo')),
      substring('bar', 1, number(not(true)) * string-length('bar'))
    )
    

    We might be able to do this using JSON-Path in JavaScript and leveraging script eval; I think it should look like this (slit-up for better readability):

    $.[?(@.conditionalField && @.dict[0].id && @.dict[1].id && @.temp.concat( 
              @.dict[0].id.substring(0, @.conditionalField==='ab' * @.dict[0].id.length()) ) 
     .concat( @.dict[1].id.substring(0, @.conditionalField==='xy' * @.dict[1].id.length()) )
       )]
    

    but it is not working. So, as of now, there seems to be no way to mimic an if-else construct in JSON-Path directly.

    A practical approach is selecting both properties separately and make the decision in your host environment:

    $.[?(@.conditionalField=='ab')].dict[0].id
    $.[?(@.conditionalField=='xy')].dict[1].id