JavaScript object query language, and a library to process and perform Jora queries on data.
STATUS: Jora is stable, but syntax may change in next releases. Still very much work in progress (ideas and thoughts).
Features:
- Tolerant to data stucture queries (e.g. just returns nothing for paths that not reachable)
- Compact syntax for common tasks
- Aggregate values across arrays and eliminate duplicates by default
- Stat collecting mode (powers suggestions)
- Tolerant parsing mode (useful to provide suggestions for query in an editor)
- Extensible DSL on query build by custom method list
Related projects:
- Discovery – Uses jora as core fuctionality to transform a data flow for views and query data for reports
- JsonDiscovery – a browser’s extension based on Discovery for viewing JSON documents, available for Chrome and Firefox (read more Changing a way we’re viewing JSON in a browser)
- jora-cli – Command line interface for transforming data using Jora
- Jora sandbox – A Web interface where you can play with jora syntax or transform some JSON with zero setup
Table of content:
Jora is a query language designed for JSON-like data structures. It extends JSON5 and shares many similarities with JavaScript.
See Docs & playground.
// single-line comment/* multi-linecomment */Jora expressions are the building blocks of Jora queries. Expressions can include comments, literals, operators, functions, and variables.
Jora supports literals, which include:
- Numbers:
42,-3.14,6.022e23 - Strings:
"hello",'world',`template${yes}`,"\u{1F600}" - Booleans:
true,false - Regular expressions:
/regexp/flags - Object literals:
{ hello: 'world' }(see Object literals) - Array literals:
[1, 2, 3](see Array literals) - Functions:
=> …(see Functions) - Keywords:
NaN,Infinity,nullandundefined
See Literals
Jora supports most JavaScript operators, including:
- Arithmetic:
+,-,*,/,% - Comparison:
=,!=,<,<=,>,>=,~= - Logical:
and,or,not(aliasno),??,is,in,not in,has,has no - Ternary:
?: - Grouing:
( ) - Pipeline:
|
See Operators
Jora provides notations for accessing properties and elements: dot, bracket and slice notations. Dot notation is similar to JavaScript's property access notation, using a period followed by the property name (e.g., $.propertyName). Bracket notation encloses the property name or index within square brackets (e.g., $['propertyName'] or $[0]), it's also possible to use functions to choose. Slice notation provides a concise syntax to slice elements with optional step (array[5:10:2] selects each odd element from 5th to 10th indecies).
Jora provides a rich set of built-in methods for manipulating data, such as map(), filter(), group(), sort(), reduce(), and many others. You can also define custom functions using the => arrow function syntax, and use them as a method.
- Functions
- Methods
- Built-in methods
- Grouping:
group()method - Sorting:
sort()method
Jora has a concise syntax for mapping and filtering. The map(fn) method is equivalent to .(fn()), while the filter(fn) method is equivalent to .[fn()].
- Filtering:
.[…]andfilter()method - Mapping:
.(…)andmap()method - Recursive mapping:
..(…)
Variables in Jora are helpful for storing intermediate results or simplifying complex expressions. To define a variable, use the $variableName: expression; syntax.
See Variables
Install with npm:
npm install jora
Basic usage:
// ESMimportjorafrom'jora';// CommonJSconstjora=require('jora');Bundles are available for use in a browser:
dist/jora.js– minified IIFE withjoraas global
<scriptsrc="node_modules/jora/dist/jora.js"></script><script>jora('query')(data,context);</script>dist/jora.esm.js– minified ES module
<scripttype="module">importjorafrom'node_modules/jora/dist/jora.esm.js'// ...</script>By default (for short path) a ESM version is exposing. For IIFE version a full path to a bundle should be specified. One of CDN services like unpkg or jsDelivr can be used:
jsDeliver<!-- ESM --><scripttype="module">importjorafrom'https://cdn.jsdelivr.net/npm/jora';</script>
<!-- IIFE with an export `jora` to global --><scriptsrc="https://cdn.jsdelivr.net/npm/jora/dist/jora.js"></script>
unpkg<!-- ESM --><scripttype="module">importjorafrom'https://unpkg.com/jora';</script>
<!-- IIFE with an export `jora` to global --><scriptsrc="https://unpkg.com/jora/dist/jora.js"></script>
importjorafrom'jora';// create a queryconstquery=jora('foo.bar');// perform a queryconstresult=query(data,context);See the details in Jora library API
Get npm dependency paths (as a tree) that have packages with more than one version:
importjorafrom'jora';import{exec}from'child_process';functionprintTree(){// see implementation in examples/npm-ls.js}exec('npm ls --all --json',(error,stdout)=>{if(error){return;}constnpmTree=JSON.parse(stdout);constdepsPathsToMultipleVersionPackages=jora(` $normalizedDeps: => dependencies.entries().({ name: key, ...value }); $multiVersionPackages: ..$normalizedDeps() .group(=>name, =>version) .({ name: key, versions: value.sort() }) .[versions.size() > 1]; $pathToMultiVersionPackages: => .($name; { name, version, otherVersions: $multiVersionPackages[=>name=$name].versions - version, dependencies: $normalizedDeps() .$pathToMultiVersionPackages() .[name in $multiVersionPackages.name or dependencies] }); $pathToMultiVersionPackages() `)(npmTree);printTree(depsPathsToMultipleVersionPackages);});Example of output:
jora@1.0.0
├─ c8@7.11.0
│ ├─ istanbul-lib-report@3.0.0
│ │ └─ supports-color@7.2.0 [more versions: 8.1.1]
│ ├─ test-exclude@6.0.0
│ │ └─ minimatch@3.1.2 [more versions: 3.0.4]
│ ├─ v8-to-istanbul@8.1.1
│ │ └─ convert-source-map@1.8.0
│ │ └─ safe-buffer@5.1.2 [more versions: 5.2.1]
│ ├─ yargs-parser@20.2.9 [more versions: 20.2.4]
│ └─ yargs@16.2.0
│ └─ yargs-parser@20.2.9 [more versions: 20.2.4]
├─ eslint@8.10.0
│ ├─ @eslint/eslintrc@1.2.0
│ │ ├─ ignore@4.0.6 [more versions: 5.2.0]
│ │ └─ minimatch@3.1.2 [more versions: 3.0.4]
...
See more examples in Complex Jora query examples