Skip to content

List indexing and querying

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

This page describes how to create a secondary index on bins whose data type is a list.

Indexing on List elements

  • Similar to basic indexing, the indexable List element data types are numeric, string, and GeoJSON.
  • You can index a List at any depth, up to the 64-level CDT nesting limit (Database 8.2.0 and later). Prior to Database 6.1.0, List indexing was only on the top-level element, not nested elements.
  • When creating an index, specify explicitly that List bins should be indexed, and what data type to index on.
  • When querying, specify that the query should be applied on a CDT data type.
  • Similar to basic querying, equality, range for integer and string data types, points-within-region, region-containing-points for GeoJSON data type are supported.

The following example uses asadm to create two indexes on a single List, one for integer values and one for string values. For further instructions, see Secondary index queries.

Terminal window
Admin+> manage sindex create integer foo_list_int in list ns test set demo bin foo
Admin+> manage sindex create string foo_list_string in list ns test set demo bin foo

Elements of the indexed list are type checked, so a record whose foo bin contains [ 1, "2", 3, [4], 5 ] results in the following indexing:

Index OnKey TypeIndex TypeEligible Secondary Index Key
foostringLIST”2”
foointegerLIST1, 3, 5

List index queries

The following example inserts three records, creates a string list index, and queries for records whose emails list contains a specific value.

Insert data

Two records have a list of email addresses in the emails bin. The third stores a scalar string instead of a list.

PKusernameemails
"u1""Bob Roberts"["bob.roberts@gmail.com", "bob@yahoo.com"]
"u2""rocketbob"["bigb@gmail.com", "bob@yahoo.com"]
"u3""samunwise""pppreciousss@gmail.com" (scalar string)
import com.aerospike.client.sdk.Cluster;
import com.aerospike.client.sdk.ClusterDefinition;
import com.aerospike.client.sdk.DataSet;
import com.aerospike.client.sdk.Session;
import com.aerospike.client.sdk.policy.Behavior;
import java.util.List;
Cluster cluster = new ClusterDefinition("127.0.0.1", 3000).connect();
Session session = cluster.createSession(Behavior.DEFAULT);
DataSet demo = DataSet.of("test", "demo");
session.upsert(demo.id("u1"))
.bin("username").setTo("Bob Roberts")
.bin("emails").setTo(List.of("bob.roberts@gmail.com", "bob@yahoo.com"))
.execute();
session.upsert(demo.id("u2"))
.bin("username").setTo("rocketbob")
.bin("emails").setTo(List.of("bigb@gmail.com", "bob@yahoo.com"))
.execute();
session.upsert(demo.id("u3"))
.bin("username").setTo("samunwise")
.bin("emails").setTo("pppreciousss@gmail.com")
.execute();

Create the list index

Use asadm to create a string index on the list elements of the emails bin:

Terminal window
Admin+> manage sindex create string email_idx in list ns test set demo bin emails

Query the list index

Query for records whose emails list contains a specific string value.

Query 1: Find records where emails contains "bigb@gmail.com" — matches 1 record (rocketbob).

Query 2: Find records where emails contains "bob@yahoo.com" — matches 2 records (Bob Roberts and rocketbob), since both lists contain that address.

Query 3: Find records where emails contains "pppreciousss@gmail.com" — matches 0 records, because that value is stored as a scalar string (not inside a list), so the list index does not cover it.

import com.aerospike.client.sdk.RecordStream;
// Query 1: emails contains "bigb@gmail.com"
try (RecordStream rs = session.query(demo).where("'bigb@gmail.com' in $.emails").execute()) {
rs.forEachRemaining(r -> System.out.println(r.recordOrThrow().getString("username")));
}
// Output: rocketbob
// Query 2: emails contains "bob@yahoo.com"
try (RecordStream rs = session.query(demo).where("'bob@yahoo.com' in $.emails").execute()) {
rs.forEachRemaining(r -> System.out.println(r.recordOrThrow().getString("username")));
}
// Output, in no guaranteed order:
// Bob Roberts
// rocketbob
// Query 3: emails contains "pppreciousss@gmail.com"
try (RecordStream rs = session.query(demo).where("'pppreciousss@gmail.com' in $.emails").execute()) {
rs.forEachRemaining(r -> System.out.println(r.recordOrThrow().getString("username")));
}
// Output: (none)

The third query returns no results because "pppreciousss@gmail.com" is stored as a scalar string in record u3, not as an element inside a list. The list index only covers values that are elements of a list bin. Querying without the list index (WHERE emails = "pppreciousss@gmail.com") would result in an AEROSPIKE_ERR_INDEX_NOT_FOUND error. A Developer SDK query that allows the scan with allowScansWithWhere runs as a primary-index query instead, reading every record in the set, and returns samunwise. See Control PI fallback.

Known limitations

When using range queries on lists, records can be returned multiple times if the list contains multiple values that fall within the range.