Skip to content

JSON.GET: unable to correlate field name with value when using with multiple fields #1307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
luca-bassoricci opened this issue Dec 24, 2024 · 3 comments

Comments

@luca-bassoricci
Copy link

Giving a json with this schema:

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    }
  }
}

and this json data

{
  "firstName": "first",
  "age": 37
}

command JSON.GET key '$.["firstName","lastName","age"]' return ["first",37] but no indication about missing value; this is particular annoying because it's not possible to match returned values list with the associated fields.

Is there any way to solve (or workaround) the problem?

@luca-bassoricci luca-bassoricci changed the title JSON.GET: unable to match field name with its value when using with multiple fields JSON.GET: unable to correlate field name with value when using with multiple fields Dec 24, 2024
@LiorKogan
Copy link
Member

LiorKogan commented Dec 24, 2024

Let us start with the following JSON:

JSON.SET k $ '[{"first":"f1", "last":"l1", "age":1},{"first":"f2", "age":2},{"last":"l3", "age":3},{"first":"f4", "last":"l4"}]'
OK

You can either retrieve all the details of each person:

JSON.GET k '$'
[[{"first":"f1","last":"l1","age":1},{"first":"f2","age":2},{"last":"l3","age":3},{"first":"f4","last":"l4"}]]

or specific fields' values - but then you'll get just an array without being able to correlate a value with a field:

JSON.GET k '$.*["first","last","age"]'
["f1","l1",1,"f2",2,"l3",3,"f4","l4"]

or without being able to correlate a field with a person:

JSON.GET k '$.*["first"]' '$.*["last"]' '$.*["age"]'
{"$.*[\"first\"]":["f1","f2","f4"],"$.*[\"last\"]":["l1","l3","l4"],"$.*[\"age\"]":[1,2,3]}

For expressions such as JSON.GET obj1 '$["a","c","b","d"]' - if the match is an object and has no member with a given name - this member is skipped. Unfortunately, you cannot tell which members were skipped.

We're aware of this issue. Similar issues:

There is no way for us to fix it without introducing breaking changes to the structure of our results.
This is planned for the future (there is no specific date I can share).

One strategy that may help with your use case (or may not) is to break the query into several queries. For example:

First, we'll retrieve the first and last name of any person who has both first and last name:

JSON.GET k '$[? @.first && @.last]["first", "last"]'
["f1","l1","f4","l4"]

Next, we'll retrieve the first name of any person who has a first name but no last name:

JSON.GET k '$[? @.last!=@.last].first'
["f2"]

Finally, we'll retrieve the last name of any person who has a last name but no first name:

JSON.GET k '$[? @.first!=@.first].last'
["l3"]

You can of course combine it into a single query as well:

JSON.GET k '$[? @.first && @.last]["first", "last"]' '$[? @.last!=@.last].first' '$[? @.first!=@.first].last'

@luca-bassoricci
Copy link
Author

Thanks for yor reply! Very appreciated.
My JSON queries are a bit different than my examples (my JSON is 4 level nested parent-child with every item identified by an UUID) and queries are often a deep search (..)

JSON.GET k '$.data..[?(@.ID == "<id to match>"].field1' '$.data..[?(@.ID == "<id to match>"].field2' '$.data..[?(@.ID == "<id to match>"].fieldN'

and I have some concern about performance due to penalty executing the same $.data..[?(@.ID == "<id to match>"] for every single field; I'm asking that because I have tried multiple query approach as well single query pattern with [.name[,.name]] pattern and there is a noticiable difference in performance in favor or latter approach.

Is there any optimization about this type of search pattern (I think about executing the $.data..[?(@.ID == "<id to match>"] once and reuse its result for the subsequent read?

@LiorKogan
Copy link
Member

Sorry, I don't have any suggestions.

We have a plan to revise the way we reply.

JSON.SET obj1 $ '{"a":1, "b":2}'
JSON.GET obj1 '$["a", "c", "b", "d"]'
[1,2]                     // which object member do these new values relate to?

After the change, the RESP3 reply would be:

1# ".a" => (integer) 1
2# ".b" => (integer) 2

Here is another example:

JSON.SET key1 $ '{"c":[1,2,3], "b":[1,2,3,4], "a":[1,2,3,4,5]}'
OK
JSON.ARRTRIM key1 $.* 0 -2
1) (integer) 2                     // which object member do these new lengths relate to?
2) (integer) 3
3) (integer) 4

After the suggested change, the reply would be:

1# ".c" => (integer) 2             // absolute path --> new length
1# ".b" => (integer) 3
1# ".a" => (integer) 4

This is a large and breaking change. It is part of an even larger effort to solve some problems with the current API.

Unfortunately, I cannot share any timeline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants