Home

Awesome

JSONPath

JSONPath is an Erlang-based fast JSON data retrieval and update module. It operates on binary data and uses jiffy for fast and efficient decoding of binary JSON into structured Erlang terms and back again.

JSONPath is simple

For example, this simple JSON document:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

Can be searched with JavaScript-like notation in binary:

(jsonpath@127.0.0.1)1> {ok, Data} = file:read_file("test.json").
{ok,<<"{\"menu\": {\n  \"id\": \"file\",\n  \"value\": \"File\",\n  \"popup\": {\n    \"menuitem\": [\n      {\"value\": \"New\", \"onclick"...>>}
(jsonpath@127.0.0.1)2> jsonpath:search(<<"menu.popup.menuitem[1].onclick">>, Data).
<<"OpenDoc()">>
(jsonpath@127.0.0.1)3>

JSONPath is fast

Using an 80KB Foursquare API venue search document to read a very specific node deep in the document can produce a result like so:

(jsonpath@127.0.0.1)4> jsonpath:search(<<"response.venues[6].categories[0].shortName">>, Data2).
<<"Sushi">>
(jsonpath@127.0.0.1)5>

Pre-decode the binary document into a structured Erlang term (via jiffy) and run that query one million times:

(jsonpath@127.0.0.1)3> JiffyData = jiffy:decode(Data2).
{[{<<"meta">>,{[{<<"code">>,200}]}},
  {<<"notifications">>,
   [{[{<<"item">>,{[{<<"unreadCount">>,2}]}},
      {<<"type">>,<<"notificationTray">>}]}]},
      ...
(jsonpath@127.0.0.1)4> jsonpath_tests:bench(jsonpath, search, [<<"response.venues[6].categories[0].shortName">>, JiffyData], 1000000).
Range: 0 - 8853 mics
Median: 5 mics
Average: 5 mics
5
(jsonpath@127.0.0.1)5>

That's 5 microseconds on average on a MacBook Pro.

JSONPath can alter your data

Using the same small JSON document from the first example, replace the content of a single node:

(jsonpath@127.0.0.1)9> Json = jsonpath:replace(<<"menu.popup.menuitem[1].onclick">>, <<"NewFunction()">>, Data).
{[{<<"menu">>,
   {[{<<"id">>,<<"file">>},
     {<<"value">>,<<"File">>},
     {<<"popup">>,
      {[{<<"menuitem">>,
         [{[{<<"value">>,<<"New">>},
            {<<"onclick">>,<<"CreateNewDoc()">>}]},
          {[{<<"value">>,<<"Open">>},
            {<<"onclick">>,<<"NewFunction()">>}]},
          {[{<<"value">>,<<"Close">>},
            {<<"onclick">>,<<"CloseDoc()">>}]}]}]}}]}}]}
(jsonpath@127.0.0.1)10> NewData = jiffy:encode(Json).
<<"{\"menu\":{\"id\":\"file\",\"value\":\"File\",\"popup\":{\"menuitem\":[{\"value\":\"New\",\"onclick\":\"CreateNewDoc()\"},{\"value\":\"Open\","...>>
(jsonpath@127.0.0.1)11>