Skip to main content

Reading and Updating Lists

For an interactive Jupyter notebook experience: Binder

Last updated: June 22, 2021

This notebook demonstrates Java Aerospike CRUD operations (Create, Read, Update, Delete) for lists of data, focusing on server-side read and update operations, including sort.

This Jupyter Notebook requires the Aerospike Database running locally with Java kernel and Aerospike Java Client. To create a Docker container that satisfies the requirements and holds a copy of these notebooks, visit the Aerospike Notebooks Repo.

Notebook Setup

Run these first to initialize Jupyter, download the Java Client, and make sure the Aerospike Database is running.

Import Jupyter Java Integration

Make it easier to work with Java in Jupyter.

import io.github.spencerpark.ijava.IJava;
import io.github.spencerpark.jupyter.kernel.magic.common.Shell;

IJava.getKernelInstance().getMagics().registerMagics(Shell.class);

Start Aerospike

Ensure Aerospike Database is running locally.

%sh asd

Download the Aerospike Java Client

Ask Maven to download and install the project object model (POM) of the Aerospike Java Client.

%%loadFromPOM
<dependencies>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-client</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>

Start the Aerospike Java Client and Connect

Create an instance of the Aerospike Java Client, and connect to the demo cluster.

The default cluster location for the Docker container is localhost port 3000. If your cluster is not running on your local machine, modify localhost and 3000 to the values for your Aerospike cluster.

import com.aerospike.client.AerospikeClient;

AerospikeClient client = new AerospikeClient("localhost", 3000);
System.out.println("Initialized the client and connected to the cluster.");

Output:

Initialized the client and connected to the cluster.

CREATING Lists in Aerospike

Create and Print List Data

Create and print a String list and an Integer List.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

ArrayList<String> listStr = new ArrayList<String>();
listStr.add("Annette");
listStr.add("Redwood");
listStr.add("Aquamarine");
listStr.add("Pineapple");
System.out.println("String List: " + listStr);

ArrayList<Integer> listInt = new ArrayList<Integer>();
listInt.add(81);
listInt.add(3);
listInt.add(27);
listInt.add(9);
listInt.add(27);
listInt.add(1);
System.out.println("Integer List: " + listInt);

Output:

String List: [Annette, Redwood, Aquamarine, Pineapple]
Integer List: [81, 3, 27, 9, 27, 1]

Insert the Lists into Aerospike

Create a Key Object

A Key uniquely identifies a specific Record in your Aerospike server or cluster. Each key must have a Namespace and optionally a Set name.

  • In Aerospike, a Namespace is like a relational database's tablespace.
  • A Set is like a relational database table in Aerospike.
  • A Record is like a row in a relational database table.

The namespace test is configured on your Aerospike server or cluster. The rest can be defined and modified by Aerospike Java Client Code.

For additional information on the Aerospike Data Model, go

here.
import com.aerospike.client.Key;

String listSet = "listset1";
String listNamespace = "test";

Integer theKey = 0;

Key key = new Key(listNamespace, listSet, theKey);
System.out.println("Key created." );

Output:

Key created.

Create a Bin Object for Each List

A Bin is a data field in an Aerospike record.

import com.aerospike.client.Bin;

String listStrBinName = "liststrbin";
String listIntBinName = "listintbin";

Bin bin1 = new Bin(listStrBinName, listStr);
Bin bin2 = new Bin(listIntBinName, listInt);
System.out.println( "Created " + bin1 + " and " + bin2 + ".");

Output:

Created liststrbin:[Annette, Redwood, Aquamarine, Pineapple] and listintbin:[81, 3, 27, 9, 27, 1].

Create a Policy Object for Record Insertion

A Policy tells Aerospike the intent of a database operation.

For more information on policies, go

here.
import com.aerospike.client.policy.ClientPolicy;

ClientPolicy clientPolicy = new ClientPolicy();
System.out.println("Created a client policy.");

Output:

Created a client policy.

Put the List Data into Aerospike

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Key: " + theKey + ", " + listStrBinName + ": " + listStr + ", " + listIntBinName + ": " + listInt);

Output:

Key: 0, liststrbin: [Annette, Redwood, Aquamarine, Pineapple], listintbin: [81, 3, 27, 9, 27, 1]

READING Lists Elements From the Server

Now that the lists are in Aerospike, the client can return full or partial lists from bin contents. No data is modified by these ops.

Get the Record

A record can be retrieved using the key, namespace, and set name.

In the output:

  • gen is the generation number, the number of record writes.
  • exp is the expiration counter for the record.

For more information on both generation number and expiration, see the

Aerospike FAQ.
import com.aerospike.client.Record;

Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
System.out.println(record);

Output:

(gen:1),(exp:359404607),(bins:(liststrbin:[Annette, Redwood, Aquamarine, Pineapple]),(listintbin:[81, 3, 27, 9, 27, 1]))

Get String Elements By Index and Rank

The Aerospike API contains the operations to get list elements using index and rank.

Get the Last String

Aerospike provides operations to read list element(s) by index. As a convenience, the client returns the specified value as the contents of the bin.

Aerospike operations allow indexing forward from the beginning of the list using zero-based numbering. Negative numbers index backwards from the end of a list.

For more examples of indexes, go here.

import com.aerospike.client.Operation;
import com.aerospike.client.Value;
import com.aerospike.client.cdt.ListOperation;

int last = -1;

Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record lastString = client.operate(null, key,
ListOperation.get(listStrBinName, last)
);

System.out.println("The string list: " + record.getValue(listStrBinName));
System.out.println("The last string: " + lastString.getValue(listStrBinName));

Output:

The string list: [Annette, Redwood, Aquamarine, Pineapple]
The last string: Pineapple

Get the Highest Rank Item

Aerospike provides operations to read list item(s) by Rank. The API methods contain options prescribing what type of data to return from an operation.

For information on list ranking, go here.

For the list of return type options, go here.

import com.aerospike.client.cdt.ListReturnType;

int highestRank = -1;

Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record highestRankString = client.operate(null, key,
ListOperation.getByRank(listStrBinName, highestRank, ListReturnType.VALUE)
);

System.out.println("The string list: " + record.getValue(listStrBinName));
System.out.println("The highest rank string: " + highestRankString.getValue(listStrBinName));

Output:

The string list: [Annette, Redwood, Aquamarine, Pineapple]
The highest rank string: Redwood

Get Integer Elements By Value Range and Rank Range

Read integer values from the Aerospike Server or Cluster using value range or rank range.

Get Integers Between 3 and 27

In addition to reading list elements by rank and index, Aerospike operations can return a Range of elements by value.

  • The lower bound of a range is included.
  • The upper bound of a range is excluded.

For more examples of ranges, go here.

int lowerBound = 3;
int upperBound = 27;

Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record between3And27 = client.operate(null, key,
ListOperation.getByValueRange(listIntBinName, Value.get(lowerBound), Value.get(upperBound),
ListReturnType.VALUE)
);

System.out.println("The integer list: " + record.getValue(listIntBinName));
System.out.println("The integers between " + lowerBound + " and " + upperBound + ": "
+ between3And27.getValue(listIntBinName));

Output:

The integer list: [81, 3, 27, 9, 27, 1]
The integers between 3 and 27: [3, 9]

Get the 2nd and 3rd Ranked Integers

Aerospike provides operations to return a range of elements by rank. Rank is zero-based.

int secondRank = 1;
int rangeRankSize = 2;

Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record rank1And2 = client.operate(client.writePolicyDefault, key,
ListOperation.getByRankRange(listIntBinName, secondRank, rangeRankSize, ListReturnType.VALUE)
);

System.out.println("The integer list: " + record.getValue(listIntBinName));
System.out.println("The 2nd and 3rd ranked integers: " + rank1And2.getValue(listIntBinName));

Output:

The integer list: [81, 3, 27, 9, 27, 1]
The 2nd and 3rd ranked integers: [9, 3]

UPDATING Lists on the Aerospike Server

Aerospike's list operations can also modify data in the Aerospike Database.

Update the String List in Aerospike

Insert a Fish into the Second and Second-from-last Position

Aerospike's list insert operation inserts before the item at an index, and increases the index of the item at the index and all subsequent items in the list.

String Fish = "Koi";
int secondPosition = 1;
int beforeLastPosition = -1;

Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listStrBinName));

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.insert(listStrBinName, beforeLastPosition, Value.get(Fish)),
ListOperation.insert(listStrBinName, secondPosition, Value.get(Fish))
);

Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listStrBinName));

Output:

Before – [Annette, Redwood, Aquamarine, Pineapple]
After – [Annette, Koi, Redwood, Aquamarine, Koi, Pineapple]

Remove By Index from the String List

int firstPosition = 0;

Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listStrBinName));

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.remove(listStrBinName, firstPosition)
);

Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listStrBinName));

Output:

Before – [Annette, Koi, Redwood, Aquamarine, Koi, Pineapple]
After – [Koi, Redwood, Aquamarine, Koi, Pineapple]

Update the Integer List in Aerospike

Append 17 to the List

int seventeen = 17;

Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listIntBinName));

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.append(listIntBinName, Value.get(seventeen))
);

Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listIntBinName));

Output:

Before – [81, 3, 27, 9, 27, 1]
After – [81, 3, 27, 9, 27, 1, 17]

Increment the 4th Integer by 111

Indexes into lists start at 0.

int incNum = 111;
int incIndex = 3;

Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listIntBinName) );

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.increment(listIntBinName, incIndex, Value.get(incNum))
);

Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listIntBinName) );

Output:

Before – [81, 3, 27, 9, 27, 1, 17]
After – [81, 3, 27, 120, 27, 1, 17]

Sorting the Lists in the Aerospike Java Client

Aerospike also provides both:

  1. An operation to sort lists in the client and optionally remove duplicates.
  2. An operation to store list data in order.

For information on maintaining list data in order, go here.

Sort the String and Drop Duplicates

For information on the flags specifying whether to remove duplicates, go here.

import com.aerospike.client.cdt.ListSortFlags;

Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Unsorted – " + origRecord.getValue(listStrBinName));

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.sort(listStrBinName, ListSortFlags.DROP_DUPLICATES)
);

Record finalRecord = client.get(null, key);
System.out.println(" Sorted – " + finalRecord.getValue(listStrBinName));

Output:

Unsorted – [Koi, Redwood, Aquamarine, Koi, Pineapple]
Sorted – [Aquamarine, Koi, Pineapple, Redwood]

Sort the Integer List and Keep Duplicates

Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Unsorted – " + origRecord.getValue(listIntBinName));

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.sort(listIntBinName, ListSortFlags.DEFAULT)
);

Record finalRecord = client.get(null, key);
System.out.println(" Sorted – " + finalRecord.getValue(listIntBinName));

Output:

Unsorted – [81, 3, 27, 120, 27, 1, 17]
Sorted – [1, 3, 17, 27, 27, 81, 120]

Notebook Cleanup

Truncate the Set

Truncate the set from the Aerospike Database.

import com.aerospike.client.policy.InfoPolicy;
InfoPolicy infoPolicy = new InfoPolicy();

client.truncate(infoPolicy, listNamespace, listSet, null);
System.out.println("Set truncated.");

Output:

Set truncated.

Close the Connection to Aerospike

client.close();
System.out.println("Server connection closed.");

Output:

Server connection closed.

Code Summary

Here is a collection of all of the non-Jupyter code from this tutorial.

Overview

  1. Import Java Libraries.
  2. Import Aerospike Client Libraries.
  3. Start the Aerospike Client.
  4. Create Test Data.
  5. Put Record into Aerospike.
  6. Get Data from Aerospike.
    1. Get the Record.
    2. Get the Last String and Highest Rank.
    3. Get Integers Between 3 and 27.
    4. Get 2 Integers By Rank Starting with the Second Rank Item.
  7. Update the Record in Aerospike
    1. Add Koi twice to the String List.
    2. Remove the Name from the String List.
    3. Append 17 to the Integer List.
    4. Increment the 4th Integer by 111.
    5. Sort the Strings and Drop Duplicates.
    6. Sort the Integers and Keep Duplicates.
  8. Truncate the Set.
  9. Close the Client Connections.
// Import Java Libraries.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


// Import Aerospike Client Libraries.

import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.policy.ClientPolicy;
import com.aerospike.client.Record;
import com.aerospike.client.Operation;
import com.aerospike.client.Value;
import com.aerospike.client.cdt.ListOperation;
import com.aerospike.client.cdt.ListReturnType;
import com.aerospike.client.cdt.ListSortFlags;
import com.aerospike.client.policy.InfoPolicy;


// Start the Aerospike Client.

AerospikeClient client = new AerospikeClient("localhost", 3000);
System.out.println("Initialized the client and connected to the cluster.");


// Create Test Data.

ArrayList<String> listStr = new ArrayList<String>();
listStr.add("Annette");
listStr.add("Redwood");
listStr.add("Aquamarine");
listStr.add("Pineapple");
System.out.println("Created String List: " + listStr);

ArrayList<Integer> listInt = new ArrayList<Integer>();
listInt.add(81);
listInt.add(3);
listInt.add(27);
listInt.add(9);
listInt.add(27);
listInt.add(1);
System.out.println("Created Integer List: " + listInt);


// Put Record into Aerospike.

String listSet = "listset1";
String listNamespace = "test";
String listStrBinName = "liststrbin";
String listIntBinName = "listintbin";
ClientPolicy clientPolicy = new ClientPolicy();
InfoPolicy infoPolicy = new InfoPolicy();


Integer theKey = 0;

Key key = new Key(listNamespace, listSet, theKey);
Bin bin1 = new Bin(listStrBinName, listStr);
Bin bin2 = new Bin(listIntBinName, listInt);
client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Inserted Key: " + theKey + ", " + listStrBinName + ": " + listStr + ", " + listIntBinName + ": " + listInt);


// Get Data from Aerospike.
// 1. Get Record.
// 2. Get the Last String and Highest Rank.
// 3. Get Integers Between 3 and 27.
// 4. Get 2 Integers By Rank Starting with the Second Rank Item.

int last = -1;
int highestRank = -1;
int lowerBound = 3;
int upperBound = 27;
int secondRank = 1;
int rangeRankSize = 2;

Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record postOp = client.operate(client.writePolicyDefault, key,
ListOperation.get(listStrBinName, last),
ListOperation.getByRank(listStrBinName, highestRank, ListReturnType.VALUE),
ListOperation.getByValueRange(listIntBinName, Value.get(lowerBound), Value.get(upperBound),
ListReturnType.VALUE),
ListOperation.getByRankRange(listIntBinName, secondRank, rangeRankSize, ListReturnType.VALUE)
);

List<?> returnStr = postOp.getList(listStrBinName);
List<?> returnIntList = postOp.getList(listIntBinName);

System.out.println("Read the Full Record From Aerospike:" + record);
System.out.println("The last string: " + returnStr.get(0));
System.out.println("The highest rank string: " + returnStr.get(1));
System.out.println("The integers between " + lowerBound + " and " + upperBound + ": "
+ returnIntList.get(0));
System.out.println("The 2nd and 3rd ranked integers: " + returnIntList.get(1));


// Update the Record in Aerospike
// 1. Add Koi twice to the String List.
// 2. Remove the Name from the String List.
// 3. Append 17 to the Integer List.
// 4. Increment the 4th Integer by 111.
// 5. Sort the Strings and Drop Duplicates.
// 6. Sort the Integers and Keep Duplicates.

String Fish = "Koi";
int fishIndex0 = 1;
int fishIndex1 = -1;
int nameIndex = 0;
int seventeen = 17;
int incNum = 111;
int incIndex = 3;

origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.insert(listStrBinName, fishIndex0, Value.get(Fish)),
ListOperation.insert(listStrBinName, fishIndex1, Value.get(Fish)),
ListOperation.remove(listStrBinName, nameIndex),
ListOperation.append(listIntBinName, Value.get(seventeen)),
ListOperation.increment(listIntBinName, incIndex, Value.get(incNum)),
ListOperation.sort(listStrBinName, ListSortFlags.DROP_DUPLICATES),
ListOperation.sort(listIntBinName, ListSortFlags.DEFAULT)
);

List<?> opStrResults = origRecord.getList(listStrBinName);
List<?> opIntResults = origRecord.getList(listIntBinName);

Record finalRecord = client.get(null, key);
System.out.println("Inserted " + Fish + "; " + listStrBinName + " size is now: " + opStrResults.get(0));
System.out.println("Inserted " + Fish + "; " + listStrBinName + " size is now: " + opStrResults.get(1));
System.out.println("Removed item at index " + nameIndex + "; removed " + opStrResults.get(2) + " item");
System.out.println("Appended " + seventeen + ", " + listIntBinName + " size is now " + opIntResults.get(0));
System.out.println("Incremented item at index " + incIndex + " by " + incNum + "; new value is: " + opIntResults.get(1));
System.out.println("Sorted both lists and removed duplicates in " + listStrBinName);
System.out.println("After Record Edits – " + finalRecord);


// Truncate the Set.

client.truncate(infoPolicy, listNamespace, listSet, null);
System.out.println("Set truncated.");

// Close the Client Connections.

client.close();
System.out.println("Closed client connections.");

Output:

Initialized the client and connected to the cluster.
Created String List: [Annette, Redwood, Aquamarine, Pineapple]
Created Integer List: [81, 3, 27, 9, 27, 1]
Inserted Key: 0, liststrbin: [Annette, Redwood, Aquamarine, Pineapple], listintbin: [81, 3, 27, 9, 27, 1]
Read the Full Record From Aerospike:(gen:1),(exp:359404610),(bins:(liststrbin:[Annette, Redwood, Aquamarine, Pineapple]),(listintbin:[81, 3, 27, 9, 27, 1]))
The last string: Pineapple
The highest rank string: Redwood
The integers between 3 and 27: [3, 9]
The 2nd and 3rd ranked integers: [9, 3]
Inserted Koi; liststrbin size is now: 5
Inserted Koi; liststrbin size is now: 6
Removed item at index 0; removed 1 item
Appended 17, listintbin size is now 7
Incremented item at index 3 by 111; new value is: 120
Sorted both lists and removed duplicates in liststrbin
After Record Edits – (gen:2),(exp:359404610),(bins:(liststrbin:[Aquamarine, Koi, Pineapple, Redwood]),(listintbin:[1, 3, 17, 27, 27, 81, 120]))
Set truncated.
Closed client connections.

Takeaway – Aerospike Does Lists

Aerospike and its Java Client are up to the task of working with your list data. APIs contain rich operations to read and update list data using index, value, and rank.

What's Next?

Next Steps

Have questions? Don't hesitate to reach out if you have additional questions about working with lists at https://discuss.aerospike.com/.

Want to learn about modeling using Lists? See, Modeling Using Lists.

Want to check out other Java notebooks?

  1. Hello, World
  2. Reading and Updating Maps
  3. Aerospike Query and UDF

Are you running this from Binder? Download the Aerospike Notebook Repo and work with Aerospike Database and Jupyter locally using a Docker container.

Additional Resources