An Introduction to JSON Selector

rezigned

Rezigned

Posted on January 25, 2020

An Introduction to JSON Selector

Cover: https://unsplash.com/photos/l5Tzv1alcps

What is JSON selector?

It's a library/tool that allows you to select values from JSON object using specific query syntax (or you can think of it as a CSS Selector but it's for JSON).

In this post, we'll go through some of the most popular libraries and see how we can use it to select our data.

What about Optional Chaining?

Before we begin. Let's take a look at ECMAScript's new proposal Optional Chaining.

When working with JS Object. Most of the time we'll come across these problems.

let user = { address: { city: "Bangkok" }, friends: [] }

How can I access city property safely? One could do

user.address && user.address.city // "Bangkok"

But what if the property that we want is in much deeper level? Then you would have to do many a && a.b && a.b.c ....

Thus, the birth of Optional Chaining Operator (?.)

The Optional Chaining Operator allows a developer to handle many of those cases without repeating themselves and/or assigning intermediate results in temporary variables:

Let's see them in action.

user?.address?.city // Bangkok

That's neat. It's much easier to access the nested property. But what if the target property is not an Object? (e.g. Array, etc.). Then the above solution won't work.

user?.friends?. // ???

JSON Selectors

The above problem can be solved with JSON selector. With this, we can now have more flexible and powerful ways to access our JSON object. We'll start with a basic JSON data.

Example

Here's the typical JSON object structure that everyone is familiar with.

{
  "users": [
    {
      "id": 1, "friends": [{ "name": "John"}]
    },
    {
      "id": 2, "friends": [{ "name": "Joe" }]
    }
  ]
}

Let's say we want to get all user ids.

[1, 2]

We'll take a look at how to achieve the above result by exploring some of the popular libraries/tools out there.

JSONPath

JSONPath's idea is to bring the power of XPath (XML-based path selector) to Javascript world.

Selecting values

With JSONPath we can achieve that by using the following path selector.

let jp = require('jsonpath')

jp.query(users, '$.users[*].id') // [1, 2]

It also supports array slice feature. In the following example it will slice an array from 0th index to 1st index (coresponds to array.slice(0, 1))

jp.query(users, '$.users[:1].id') // [1]

One of the problem that I stumbled upon is that. It always returns array of values eventhough I explicity specify the index of an array e.g.

jq.query(users, '$.users[0].id') // [1], should just return single element i.e. 1

There're many path expressions that you might want to check it out https://goessner.net/articles/JsonPath/index.html#e2

Here's the playground.

jq

jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text

jq is very popular and powerful one. It can even transform your output and has become part of many command line tools. You've probably seen it in many tutorials that deal with cli and json.

Let's take a quick look.

Selecting values

A simple example.

$ curl <url> | jq '.users[].id' // [1, 2]

Transforming values

It can do more than just selecting. In the example below, we can even produce a new JSON output with pipe operators (|).

$ curl <url> | jq '.users[0] | { "id": .id }' // { "id": 1 }

Explanation It selects the first element of users array and then creates a new object by using id property of the result from previous command.

Here's the playground.

@gizt/selector

@gizt/selector disclaimer: I wrote this library a while ago. Because I just want a selector with a simple syntax that every developer who uses Javascript is already familiar with.

Let's take a quick tour.

Selecting values

const s = require('@gizt/selector')

s('users[].id', users) // [1, 2]

// single value
$('users[0].id', users) // 1 (not [1])

// go deeper
s('users[].friends[].name', users) // ["John", "Joe"]

Notice that we don't have to add a prefix like . or $ at the beginning of the query.

Globing the keys

I believe that every developers is already familiar with * wildcard symbol. We can use it to filter our result even further.

Select any properties

In the following example, we select any properties of user object i.e. id and friends

s('users[].*')

[
  // users[0].id
  1,
  // users[0].friends
  [{ "name": "John"}],
  // users[1].id
  2,
  // users[1].friends
  [{ "name": "Joe"}]
]

Select only matched prefix/suffix

Here we want only property that start with i. In this case it only matches id

s('users[].i*') // [1, 2]

When we want to match a suffix we can simpy do. It'll match properties that end with ends i.e. friends

s('users[].*ends') // [[ friend 1 ], [ friend 2 ]]

The syntax is just make any developer feels at home. No need to remember any special characters. Just plain JSON notation and glob.

Playground

Summary

I just gave a quick overview on JSON Selector topic which covered some of the popular libraries out there (including my own :p). Some people might not aware of these tools/libraries which we can leverage to solve everyday's problems.

P.S it's my first article here. Hope you guys enjoy it.

If you have any libraries and feedback. Please share and comment. Have a good day :).

💖 💪 🙅 🚩
rezigned
Rezigned

Posted on January 25, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related