jmespath / jmespath.js

Javascript implementation of JMESPath, a query language for JSON
http://jmespath.org
Other
782 stars 97 forks source link

Feature request: access parent object #22

Open o0x2a opened 8 years ago

o0x2a commented 8 years ago

As a user, I want to use pipe or a modifier or a function to access the parent object.

reservations[].instances[].[tags[?Key=='Name'].Values[] | [0], type, state.name] | [..]

or

reservations[].instances[].[tags[?Key=='Name'].Values[] | [0], type, state.name] | parent(@)
apatrida commented 6 years ago

Adding a parent reference would require path tracing, which is fairly complicated to do especially through pipes and other transforms that reset the object to something fairly unrelated. I have been working on this for a port of the Java implementation and if I have successful experiments will push this back towards the spec. The issue is that such as small thing as this one function, completely makes implementation much more complicated.

In my version, I trace the query and have a full trace and the object at each step, so the trace acts as a way to get the path of any found node, but also since you have the trace, you can go upwards in a trace to find a parent. (assuming .. deep pathing traces each level it went through) ... The objects themselves typically have no upwards pointers to parents, so the engine has to know and it can via tracing.

o0x2a commented 6 years ago

How about storing reference to parent object in each child node as we navigate from root to each child? By storing the reference to the parent node we may not require path tracing.

apatrida commented 6 years ago

That is basically what tracing would do, but also crosses over pipes, collapsing arrays, and other steps.

Outside of tracing, yes parent node references could be kept from each point where you stop projection (i.e. pipe) so you can reach back up to that point. Basically a map from child->parent for each step of the tree.

mixja commented 6 years ago

One approach could be to store a reference to the original source data structure in a special variable (I was thinking $ might be a suitable identifier for this).

For example given the following input:

{
  "a": 5,
  "b": [
    {"c": 6},
    {"c": 7},
    {"c": 8}
  ]
}

It's currently impossible to generate something like this:

[
  {"a": 5, "b": 6},
  {"a": 5, "b": 7},
  {"a": 5, "b": 8}
]

With $ representing a reference to the source input, you could generate the above using the following expression:

b[].{a:$.a,b:c}

It might make sense to reset $ whenever you pipe an expression to another, given you are free to capture $ or a subtree of $ in the prior expression that is piped in.

I don't think this would be too difficult to implement - each reference to $ is another query that just needs to be evaluated from the source input.

MarkSwanson commented 6 years ago

Fyi I'm unable to use JMESPath for a product I'm building - my requirements can only be met if I have '$' functionality.

Allam76 commented 5 years ago

Using Symbol couls also be an option. Don't know how much extra complication that might lead to.

Path tracing might not be needed if we can put the parent object in the symbol. Something like this:

var parentSymbol = Symbol("parent");
obj[parentSymbol] = parent;

I've used this successfully in plain javascript.

sauron918 commented 5 years ago

+1, possibility of access to parent object will be very useful in many cases

Thaina commented 5 years ago

I want to propose @.. for parent access. Is it collide with any existing syntax?

barbu110 commented 4 years ago

Hello! Anything on this, please?

Thaina commented 4 years ago

@barbu110 It seem jmespath just set in stone. No new feature will be added and become standardized as json. Currently now I lose hope in jmespath to add new feature and am working on new parser of my own. But I still don't have good syntax for parent accessor, really harder than I thought

Allam76 commented 4 years ago

I use a method where preprocess and set a parent Symbol and then use a proxy as data input. Whenever the parent property comes up, the proxy then delegates to the symbol. This approch requires no changes to the library.

sscots commented 4 years ago

@Allam76 Can you post an example of how you handled that?

darrenmothersele commented 4 years ago

I added support for $ to access the root object in my fork of jmespath.js.

The example given above, with b[].{a:$.a,b:c} works, as you can see here:

https://codesandbox.io/s/upbeat-elgamal-xxz7s?fontsize=14&hidenavigation=1&theme=dark

I added $ as a new token (TOK_ROOT) to the lexer and parser, as you can see in this commit: https://github.com/daz-is/jmespath.js/commit/0d28f249d7b3fa6a2bafcc12227ef17f27762b01

Allam76 commented 4 years ago

Sure: jsonata parent proposal both my solution and native implementation

simlu commented 2 years ago

If this is something you are looking to do, take a look at object-scan as an alternative to jmespath. The filter functionality is more limited, but it does provide a lot of search context

Disclaimer: I'm the author