25

I am using nodejs with jsonpath. I have this json structure:

{
  things:{
    books: [
      {name: "book1"},
      {name: "book2"},
      {name: "book3"},
      {name: "book4"},
    ],
    movies: [
      {name: "movie1"},
      {name: "movie2"},
      {name: "movie3"},
      {name: "movie4"},
    ]
  }
}

I would like to know the jsonpath expression that returns an array with the key names of the things object. That would be:

["books","movies"]

For now, I am doing this:

Object.keys(jsonpath.eval(jsonStructure,"$.things").pop());

But I don't find it elegant... I should not need to get a copy the whole structure when I only need the key names.

Retsam
  • 30,909
  • 11
  • 68
  • 90
norteo
  • 1,828
  • 2
  • 13
  • 7
  • Why use JSONPath when you can just do `Object.keys(jsonStructure.things)`? – loganfsmyth Apr 21 '13 at 22:12
  • True, that would also work. But my point is to do it only with jsonpath. The idea is that the jsonpath strings will be stored in a config file. I would like to be able to affect the script behavior only changing the config file and not the code. – norteo Apr 22 '13 at 09:19

4 Answers4

10

jsonPath has new update jsonpath-plus jsonpath-plus expands on the original specification to add some additional operators and makes explicit some behaviors the original did not spell out.

^ for grabbing the parent of a matching item ~ for grabbing property names of matching items (as array)

so to get proper output use this query things.*~ you can try here also https://jsonpath.com/

klapshin
  • 761
  • 8
  • 14
Suraj Malgave
  • 133
  • 1
  • 4
3

I don't believe there is a better solution than your own:

Object.keys(jsonpath.eval(jsonStructure,"$.things").pop());

I think the main misconception here is that you don't have to worry about this snippet "getting a copy of the whole structure", because you aren't copying the whole structure. You already have the entire object loaded into memory, jsonpath doesn't create a new copy, it simply returns a reference to the already existing object, i.e.:

jsonpath.eval(jsonStructure,"$.things").pop() === jsonStructure.things //true
Retsam
  • 30,909
  • 11
  • 68
  • 90
1

Not exactly what you are asking for, but might still be relevant.

We use object-scan for this kind of task as it is much better suited for data processing and analyzing. Once you wrap your head around it that is (:

Anyways, here is how you could answer your question if you are willing to add another dependency

// const objectScan = require('object-scan');

const data = { things: { books: [ { name: 'book1' }, { name: 'book2' }, { name: 'book3' }, { name: 'book4' } ], movies: [ { name: 'movie1' }, { name: 'movie2' }, { name: 'movie3' }, { name: 'movie4' } ] } };

console.log(objectScan(['things.*'], { rtn: 'property' })(data));
// => [ 'movies', 'books' ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>

Disclaimer: I'm the author of object-scan

vincent
  • 1,953
  • 3
  • 18
  • 24
-1

The syntax you used for give is wrong to get keys in json path use "$.*~" ex. input: { "firstName": "John", "lastName" : "doe", "age" : 26 } output: [ "firstName", "lastName", "age" ]

Suraj Malgave
  • 133
  • 1
  • 4
  • Is it meant to be a new answer? Or a comment on another answer? You can [edit your previous answer](https://stackoverflow.com/posts/58959850/edit) if you want to add more details. – Zsolt Meszaros Jan 15 '21 at 16:04