jmespath.js icon indicating copy to clipboard operation
jmespath.js copied to clipboard

Feature request: access parent object

Open o0x2a opened this issue 9 years ago • 15 comments

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(@)

o0x2a avatar Sep 13 '16 12:09 o0x2a

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.

apatrida avatar Dec 08 '17 11:12 apatrida

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.

o0x2a avatar Dec 08 '17 16:12 o0x2a

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.

apatrida avatar Dec 08 '17 17:12 apatrida

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.

mixja avatar Jun 03 '18 12:06 mixja

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

MarkSwanson avatar Jun 15 '18 15:06 MarkSwanson

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.

Allam76 avatar Jan 31 '19 12:01 Allam76

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

sauron918 avatar Jun 04 '19 09:06 sauron918

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

Thaina avatar Aug 27 '19 10:08 Thaina

Hello! Anything on this, please?

barbu110 avatar Jan 13 '20 10:01 barbu110

@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

Thaina avatar Jan 13 '20 12:01 Thaina

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.

Allam76 avatar Jan 16 '20 08:01 Allam76

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

sscots avatar Mar 03 '20 18:03 sscots

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

darrenmothersele avatar Mar 03 '20 20:03 darrenmothersele

Sure: jsonata parent proposal both my solution and native implementation

Allam76 avatar Apr 15 '20 15:04 Allam76

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

simlu avatar Jul 04 '22 05:07 simlu