0

I'm working with IBM Db2 (Version 11.5) and I'm trying to query JSON data stored in a column named data which contains an array of objects. However, my query using JSON_EXISTS does not return the expected results.

JSON Structure Example

The JSON structure (simplified here) includes an array outerField, and I need to retrieve rows in which an object of outerField exists with innerField equal to "target". However, my query using JSON_EXISTS does not return the expected results.

The simplified JSON data stored in the data column looks like this:

{
  "randomField1": "randomValue",
  ...
  "outerField":
    [
      {
        "innerField": "target"
      },
      {
        "innerField": "dummy1"
      },
      {
        "innerField": "dummy2"
      }
    ]
}

Using Json Path & JSON_EXIST

I would like to use JSON Path, and using an online evaluation tool, I've found that this query should work:

$.outerField[?(@.innerField== "target")].

Given that I can't use directly JSON_VALUE with a json path like:

JSON_VALUE(data, '$.outerField[*].innerField') = 'target'

Since JSON_VALUE expects just a single value (outerField[0].innerFieldworks as expected).

I've thought that I could use Db2's JSON_EXISTS function:

SELECT *
FROM test_entity
WHERE JSON_EXISTS(
    data,
    '$.outerField[?(@.innerField== "target")]'
)

That, unfortunately, does not return any rows even though the example JSON clearly shows an object in outerField with innerField equal to "target".

Any ideas or suggestion?

** EDIT **

I think the most reasonable solution is to use the JSON_TABLE function to unnest the inner array, but I'm not sure how to proceed. I'm able to use JSON_TABLE on ordinary fields, but with arrays, I'm getting many syntax errors. For instance:

SELECT *
FROM TEST_ENTITY te, JSON_TABLE(te.data, 'lax $.outerField[*]' columns (target VARCHAR(100) PATH 'lax $.innerField') ERROR ON ERROR)  AS jt 
WHERE jt.innerField= 'target';

This query returns the following error

SQL Error [42601]: An unexpected token "lax $.outerField[*]" was found following "".  Expected tokens may include:  "strict $".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.31.10

(Even using strict instead of lax I'm receiving the same error)

2 Answers 2

0
SELECT * FROM test_entity
where json_exists(data, '$?(@.outerField[*].innerField == "target")') ;
Sign up to request clarification or add additional context in comments.

3 Comments

Hi p3consulting, Thank you for your response! Unfortunately, this approach also doesn't work (no rows are returned). I've seen some solutions that suggest using an unnesting function, but it seems complex and expensive. Do you think this task can be accomplished using JSON_EXIST?
Well I don't have DB2 at hand, I tested the expression in ORACLE (23), because I know they are quite close for that, with success... select 1 where json_exists(q'~{ "randomField1": "randomValue", "outerField": [ { "innerField": "target" }, { "innerField": "dummy1" }, { "innerField": "dummy2" } ] }~', '$?(@.outerField[*].innerField == "target")') ; returns 1 row with the value 1, so at least the syntax works on the sample data
Yes, I got it. Despite that, with DB2, this won't work. From what I've learned, JSON PATH expressions like that are unsupported for this DB (correct me if I'm wrong, future viewer who has the solution out of the box, haha). So, I tried something different (you can find it in my answer).
0

Given my frustration with the (bad, really bad) DB2-related documentation, I managed this task in a somewhat "fancy" way.

I’m not sure if this is the best solution, but it works for now. I've figured out that I could use JSON_QUERY to extract and flatten nested arrays in a JSON object.

Just like this:

SELECT JSON_QUERY(tt.JSONDOC, '$.outerField[*].innerField' WITH UNCONDITIONAL WRAPPER)
FROM TEST_TABLE tt

This query returns:

-------------------+
["targetB"]        |
["target"]         |
["dummy1"]         |
["dummy2"]         |
["target","dummy3"]|

As you can see, the result contains the flattened CLOB of the innerField values for each rows. So I've realized that I could use this approach in the WHERE clause to filter the rows as needed from the beginning.

Here’s the resulting query:

SELECT *
FROM EMPLOYEE_TABLE et
WHERE JSON_QUERY(et.JSONDOC, '$.outerField[*].innerField' WITH UNCONDITIONAL WRAPPER) LIKE '%"target"%'

That returns all the rows with at least one "innerField" equal to the "target" value!

ID|JSONDOC                                                                                                                                                                 |
--+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 2|{"id" : 901,"firstname" : "John","lastname"  : "Doe","phoneno"   : "555-3762",¶ "outerField" : [{  "innerField": "target"}]}                                            |
 5|{"id" : 901,"firstname" : "John","lastname"  : "Doe","phoneno"   : "555-3762",¶ "outerField" : [{  "innerField": "target"},{  "innerField": "dummy3"}]}|

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.