When searching for items in complex JSON arrays and hashes, like:
[
{ "id": 1, "name": "One", "objects": [
{ "id": 1, "name": "Response 1", "objects": [
// etc.
}]
}
]
Is there some kind of query language I can used to find an item in [0].objects where id = 3
?
This question is related to
javascript
json
xpath
xquery
Jsel is awesome and is based on a real XPath engine. It allows you to create XPath expressions to find any type of JavaScript data, not just objects (strings too).
You can create custom schemas and mappings to give you complete control over how your data is walkable by the XPath engine. A schema is a way of defining how elements, children, attributes, and node values are defined in your data. Then you can create your own expressions to suit.
Given you had a variable called data
which contained the JSON from the question, you could use jsel to write:
jsel(data).select("//*[@id=3]")
This will return any node with an id
attribute of 3. An attribute is any primitive (string, number, date, regex) value within an object.
Other alternatives I am aware of are
HTH.
ObjectPath is a query language similar to XPath or JSONPath, but much more powerful thanks to embedded arithmetic calculations, comparison mechanisms and built-in functions. See the syntax:
Find in the shop all shoes of red color and price less than 50
$..shoes.*[color is "red" and price < 50]
Is there some kind of query language ...
jq defines a JSON query language that is very similar to JSONPath -- see https://github.com/stedolan/jq/wiki/For-JSONPath-users
... [which] I can used to find an item in [0].objects where id = 3?
I'll assume this means: find all JSON objects under the specified key with id == 3, no matter where the object may be. A corresponding jq query would be:
.[0].objects | .. | objects | select(.id==3)
where "|" is the pipe-operator (as in command shell pipes), and where the segment ".. | objects" corresponds to "no matter where the object may be".
The basics of jq are largely obvious or intuitive or at least quite simple, and most of the rest is easy to pick up if you're at all familiar with command-shell pipes. The jq FAQ has pointers to tutorials and the like.
jq is also like SQL in that it supports CRUD operations, though the jq processor never overwrites its input. jq can also handle streams of JSON entities.
Two other criteria you might wish to consider in assessing a JSON-oriented query language are:
If you're like me and you just want to do path-based lookups, but don't care about real XPath, lodash's _.get()
can work. Example from lodash docs:
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// ? 3
_.get(object, ['a', '0', 'b', 'c']);
// ? 3
_.get(object, 'a.b.c', 'default');
// ? 'default'
Try this out - https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java
It's a very simple implementation on similar line of xpath for xml. It's names as jpath.
Try to using JSPath
JSPath is a domain-specific language (DSL) that enables you to navigate and find data within your JSON documents. Using JSPath, you can select items of JSON in order to retrieve the data they contain.
JSPath for JSON like an XPath for XML.
It is heavily optimized both for Node.js and modern browsers.
To summarise some of the current options for traversing/filtering JSON data, and provide some syntax examples...
JSPath
.automobiles{.maker === "Honda" && .year > 2009}.model
json:select() (inspired more by CSS selectors)
.automobiles .maker:val("Honda") .model
JSONPath (inspired more by XPath)
$.automobiles[?(@.maker='Honda')].model
I think JSPath looks the nicest, so I'm going to try and integrate it with my AngularJS + CakePHP app.
(I originally posted this answer in another thread but thought it would be useful here, also.)
Json Pointer seem's to be getting growing support too.
I think JSONQuery is a superset of JSONPath and thus replaces it in dojo. Then there's also RQL.
From Dojo documentation:
JSONQuery is an extended version of JSONPath with additional features for security, ease of use, and a comprehensive set of data querying tools including filtering, recursive search, sorting, mapping, range selection, and flexible expressions with wildcard string comparisons and various operators.
JSONselect has another point of view on the question (CSS selector-like, rather than XPath) and has a JavaScript implementation.
Just to add to the choices, there's also XPath. XPath 3.1 handles JSON as well as XML. In XPath 3.1 your required query is ?0?Objects?*[?id=3]
JMESPath seems to be very popular these days (as of 2020) and addresses a number of issues with JSONPath. It's available for many languages.
@Naftule - with "defiant.js", it is possible to query a JSON structure with XPath expressions. Check out this evaluator to get an idea of how it works:
http://www.defiantjs.com/#xpath_evaluator
Unlike JSONPath, "defiant.js" delivers the full-scale support of the query syntax - of XPath on JSON structures.
The source code of defiant.js can be found here:
https://github.com/hbi99/defiant.js
XQuery can be used to query JSON, provided that the processor offers JSON support. This is a straightforward example how BaseX can be used to find objects with "id" = 1:
json:parse('[
{ "id": 1, "name": "One", "objects": [
{ "id": 1, "name": "Response 1", "objects": [ "etc." ] }
]}
]')//value[.//id = 1]
I know the OP tagged the question with javascript
but in my case I was looking exactly the same thing but from a Java backend (with Camel).
An interesting thing that can also be useful if you are using an integration framework like Camel, jsonPath
is also supported by a specific Camel Component since Camel 2.13.
Example from the Camel doc above:
from("queue:books.new")
.choice()
.when().jsonpath("$.store.book[?(@.price < 10)]")
.to("jms:queue:book.cheap")
.when().jsonpath("$.store.book[?(@.price < 30)]")
.to("jms:queue:book.average")
.otherwise()
.to("jms:queue:book.expensive")
which is quite straightforward to use.
Defiant.js looks also pretty cool, here's a simple example:
var obj = {
"car": [
{"id": 10, "color": "silver", "name": "Volvo"},
{"id": 11, "color": "red", "name": "Saab"},
{"id": 12, "color": "red", "name": "Peugeot"},
{"id": 13, "color": "yellow", "name": "Porsche"}
],
"bike": [
{"id": 20, "color": "black", "name": "Cannondale"},
{"id": 21, "color": "red", "name": "Shimano"}
]
},
search = JSON.search(obj, '//car[color="yellow"]/name');
console.log( search );
// ["Porsche"]
var reds = JSON.search(obj, '//*[color="red"]');
for (var i=0; i<reds.length; i++) {
console.log( reds[i].name );
}
// Saab
// Peugeot
// Shimano
Source: Stackoverflow.com