Aerospike Document API
Published: 2021-06-17 09:45:01

[Aerospike](https://www.aerospike.com) is a high performance, distributed, scalable, key value database. Aerospike leverages SSD technology to achieve levels of throughput and low latency exceeding even those obtained with in memory products. This allows hardware costs to be reduced 10x or more and data density to be increased 10x or more versus any other high performance solution.

Aerospike has a significant number of distinguishing characteristics versus competitor products. Here we focus on the [Collection Data Type (CDT) API](https://www.aerospike.com/docs/guide/cdt.html). The CDT API facilitates list and map oriented operations within objects thereby reducing network overhead and client side computation. It is worth noting that it is highly efficient, adding little overhead to read or write calls and composable, allowing construction of complex overall operations.

The CDT API contains within it all the primitives required to build a sophisticated document API along the lines suggested by Stefan Groessner in his well known [JsonPath](https://goessner.net/articles/JsonPath/) proposal which is in turn modelled on the [XPath](https://en.wikipedia.org/wiki/XPath) standard for XML. For those not familiar with it, XPath supports CRUD operations via filesystem navigation like syntax. JsonPath is essentially a port of this idea to JSON.

The [Aerospike Document API](https://github.com/aerospike/aerospike-document-lib) provides such an API, using the CDT API. Below we demonstrate the way in which CRUD operations can be executed at arbitrary points within a JSON document using the API.

## Document Creation

First we need a JSON document to work with. Consider the below, expressing some subjective, for space reasons, highlights of [Tommy Lee Jones](https://en.wikipedia.org/wiki/Tommy_Lee_Jones) career.

```json
{
  "forenames": [
    "Tommy",
    "Lee"
  ],
  "surname": "Jones",
  "date_of_birth": {
    "day": 15,
    "month": 9,
    "year": 1946
  },
  "selected_filmography":{
    "2012":["Lincoln","Men In Black 3"],
    "2007":["No Country For Old Men"],
    "2002":["Men in Black 2"],
    "1997":["Men in Black","Volcano"],
    "1994":["Natural Born Killers","Cobb"],
    "1991":["JFK"],
    "1980":["Coal Miner's Daughter","Barn Burning"]
  },
  "imdb_rank":{
    "source":"https://www.imdb.com/list/ls050274118/",
    "rank":51
  },
  "best_films_ranked": [
    {
      "source": "http://www.rottentomatoes.com",
      "films": ["The Fugitive","No Country For Old Men","Men In Black","Coal Miner's Daughter","Lincoln"]
    },
    {
      "source":"https://medium.com/the-greatest-films-according-to-me/10-greatest-films-of-tommy-lee-jones-97426103e3d6",
      "films":["The Three Burials of Melquiades Estrada","The Homesman","No Country for Old Men","In the Valley of Elah","Coal Miner's Daughter"]
    }
  ]
}
```

Using the document API we add to our database.

```java
// Create a document client via an existing aerospikeClient
AerospikeDocumentClient documentClient = new AerospikeDocumentClient(client);

// Convert JSON string to a JsonNode
JsonNode jsonNode = JsonConverters.convertStringToJsonNode(tommyLeeJonesJson);

// Construct an appropriate key
Key tommyLeeJonesDBKey = new Key(AEROSPIKE_NAMESPACE, AEROSPIKE_SET, "src/test/resources/tommy-lee-jones.json");

// Add to database using a named bin
documentClient.put(tommyLeeJonesDBKey, documentBinName, jsonNode);
```

## Reads

We can find out the name of Jones' best film according to 'Rotten Tomatoes' using the path `$.best_films_ranked[0].films[0]`. Hopefully the use of keys and list indexes is immediately intuitive when considered in the context of the above document.

```java  
documentClient.get(tommyLeeJonesDBKey, documentBinName, "$.best_films_ranked[0].films[0]");
```

will return
```
"The Fugitive"
```

We are not limited to retrieving primitives. An expression such as

```
"$.selected_filmography.1980"
```

will retrieve a list

```json
["Coal Miner's Daughter","Barn Burning"]
```

## Updates

We can add to the document. The snippet below will add a 2019 element to the filmography.

```java
List<String> _2019Films = new Vector<String>();
_2019Films.add("Ad Astra");
documentClient.put(tommyLeeJonesDBKey, documentBinName, "$.selected_filmography.2019",_2019Films);

```

We can update document nodes directly - this syntax updates Jones' [IMDB](https://www.imdb.com/) ranking.

```java
documentClient.put(tommyLeeJonesDBKey, documentBinName, "$.imdb_rank.rank",45);
```

Append operations may also be used. For example, we can append to 'Rotten Tomatoes' list of best films using the reference `$.best_films_ranked[0].films`

 ```java
documentClient.append(tommyLeeJonesDBKey, documentBinName, "$.best_films_ranked[0].films","Rolling Thunder");
 
documentClient.append(tommyLeeJonesDBKey, documentBinName, "$.best_films_ranked[0].films","The Three Burials");
```

## Deletion

We can similarly use JsonPath like expressions to support node deletion. The line below will remove the Medium rankings from the document

```java
documentClient.delete(tommyLeeJonesDBKey, documentBinName, "$.best_films_ranked[1]");
```

## Availability

The library has been published to Maven Central as _aerospike-document-api_. Add

```xml
<dependency>
   <groupId>com.aerospike</groupId>
   <artifactId>aerospike-document-api</artifactId>
   <version>1.1.2</version>
</dependency>
```

to your *pom.xml* to use.

For full details of the API see [aerospike-document-lib](https://github.com/aerospike/aerospike-document-lib)