Skip to content

Query records

Learn how to find records in Aerospike using the Developer SDK’s AEL (Aerospike Expression Language) queries. AEL provides a readable, SQL-like syntax for filtering data.

Basic query

All operations which read data are queries, regardless of whether you are reading one record, 100 records, or performing an index query. Use query() to find records, and a where clause to provide filtering if desired:

import com.aerospike.client.sdk.DataSet;
import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordStream;
DataSet users = DataSet.of("test", "users");
RecordStream stream = session.query(users)
.where("$.status == 'active'")
.execute();
stream.forEach(result -> {
Record user = result.recordOrThrow();
System.out.println("Name: " + user.getString("name"));
});

AEL operators

Use $.binName to get the contents of a bin called binName. String literals can be in either single or double quotes, floats are numbers with a decimal point and integer are just digits.

Comparison operators

OperatorDescriptionExample
==Equal"$.status == 'active'"
!=Not equal"$.status != 'inactive'"
>Greater than"$.age > 21"
>=Greater than or equal"$.age >= 18"
<Less than"$.balance < 0"
<=Less than or equal"$.score <= 100"

See AEL reference for a complete list of AEL operators.

import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// Numeric comparisons
RecordStream s1 = session.query(users).where("$.age >= 18").execute();
s1.forEach((RecordResult result) -> { /* use result.recordOrThrow() */ });
// String equality
RecordStream s2 = session.query(users).where("$.role == 'admin'").execute();
s2.forEach((RecordResult result) -> { /* ... */ });
// Not equal
RecordStream s3 = session.query(users).where("$.deleted != true").execute();
s3.forEach((RecordResult result) -> { /* ... */ });

Logical operators

Combine conditions with and, or, and not:

import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// AND
RecordStream a = session.query(users)
.where("$.status == 'active' and $.age >= 18")
.execute();
a.forEach((RecordResult result) -> { /* ... */ });
// OR
RecordStream b = session.query(users)
.where("$.role == 'admin' or $.role == 'moderator'")
.execute();
b.forEach((RecordResult result) -> { /* ... */ });
// NOT
RecordStream c = session.query(users)
.where("not($.status == 'banned')")
.execute();
c.forEach((RecordResult result) -> { /* ... */ });
// Complex combinations
RecordStream d = session.query(users)
.where("($.status == 'active' or $.status == 'pending') and $.age >= 18")
.execute();
d.forEach((RecordResult result) -> { /* ... */ });

Membership and existence operators

OperatorDescriptionExample
inMembership in a list"'admin' in $.roles"
exists()Path/bin existence check"$.email.exists()"
count()Collection cardinality"$.tags.count() > 3"
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// Membership in list
RecordStream s1 = session.query(users)
.where("'admin' in $.roles")
.execute();
s1.forEach((RecordResult result) -> { /* ... */ });
// Exists tests for the presence of the bin in the record
RecordStream s2 = session.query(users)
.where("$.email.exists()")
.execute();
s2.forEach((RecordResult result) -> { /* ... */ });
// Collection size
RecordStream s3 = session.query(users)
.where("$.tags.count() > 3")
.execute();
s3.forEach((RecordResult result) -> { /* ... */ });

Select specific bins

Return only the bins you need:

import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
RecordStream stream = session.query(users)
.where("$.status == 'active'")
.readingOnlyBins("name", "email") // Only return name and email
.execute();
stream.forEach((RecordResult result) -> {
Record user = result.recordOrThrow();
System.out.println(user.getString("name"));
});

Limit results

Limit the number of records returned:

import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// Get first 10 active users
RecordStream stream = session.query(users)
.where("$.status == 'active'")
.limit(10)
.execute();
stream.forEach((RecordResult result) -> { /* ... */ });

Stream results

The record streams buffer results returned from the server efficiently when queries which return large numbers of results are executed. This is transparent to the API, but it means that large result sets are not loaded into memory in their entirety.

Record streams should be closed when finished, freeing up resources on both the client side and server side. In Java, terminal helpers such as getFirst, getFirstRecord, and forEach close the stream when the call finishes. In Python, helpers like first(), first_or_raise(), collect(), and failures() consume the stream but do not auto-close it; always call stream.close() (or wrap the work in a try / finally) to release client and server resources promptly.

For large result sets, stream records instead of loading all into memory:

import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// Process records one at a time
RecordStream stream = session.query(users)
.where("$.status == 'active'")
.execute();
stream.forEach((RecordResult result) -> {
if (result.isOk()) {
Record user = result.recordOrThrow();
if (user != null) {
System.out.println("Processing: " + user.getString("name"));
}
}
});

Query without filter (scan)

Query all records in a set:

import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// Get all users (use with caution on large datasets!)
RecordStream allStream = session.query(users).execute();
List<Record> allUsers = allStream.stream().asList();
// Better: stream to avoid memory issues
RecordStream scan = session.query(users).execute();
scan.forEach(result -> {
Record user = result.recordOrThrow();
System.out.println(user.getString("name"));
});

Complete example

import com.aerospike.client.sdk.Cluster;
import com.aerospike.client.sdk.ClusterDefinition;
import com.aerospike.client.sdk.DataSet;
import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
import com.aerospike.client.sdk.Session;
import com.aerospike.client.sdk.policy.Behavior;
public class QueryRecordsExample {
public static void main(String[] args) {
try (Cluster cluster = new ClusterDefinition("localhost", 3000).connect()) {
Session session = cluster.createSession(Behavior.DEFAULT);
DataSet users = DataSet.of("test", "users");
String k1 = "query-example-1";
String k2 = "query-example-2";
String k3 = "query-example-3";
String k4 = "query-example-4";
// Cleanup so the example is repeatable.
session.delete(users.ids(k1, k2, k3, k4)).execute().close();
// Create sample data
session.insert(users)
.bins("name", "age", "status")
.id(k1).values("Alice", 28, "active")
.id(k2).values("Bob", 35, "active")
.id(k3).values("Carol", 22, "inactive")
.id(k4).values("David", 45, "active")
.execute();
// Simple query
System.out.println("Active users:");
RecordStream q1 = session.query(users)
.where("$.status == 'active'")
.execute();
q1.forEach((RecordResult result) -> {
Record u = result.recordOrThrow();
System.out.println(" - " + u.getString("name"));
});
// Complex query
System.out.println("\nActive adults over 30:");
RecordStream q2 = session.query(users)
.where("$.status == 'active' and $.age > 30")
.readingOnlyBins("name", "age")
.execute();
q2.forEach(result -> {
if (result.isOk()) {
Record u = result.recordOrThrow();
System.out.println(
" - " + u.getString("name") + " (" + u.getInt("age") + ")"
);
}
});
// Count
RecordStream q3 = session.query(users)
.where("$.status == 'active'")
.execute();
long activeCount = 0;
while (q3.hasNext()) {
RecordResult rr = q3.next();
activeCount++;
}
q3.close();
System.out.println("\nActive user count: " + activeCount);
}
}
}

AEL and secondary indexes

AEL text does not force a full scan. The planner can use available secondary indexes for selective predicates and fall back to scans when no useful index exists.

📖 Learn more: AEL Reference covers the full AEL syntax.

API reference summary

MethodDescription
session.query(dataSet)Start a query on a DataSet
.where("expression")Filter with AEL expression (use $.bin for bin paths)
.readingOnlyBins(bins...) / .bins([...]) on session.query(DataSet)Select specific bins to return
.limit(n)Limit number of results
.execute()Run the query and return a RecordStream
RecordStream / async forIterate results; call stream.close() when done

Next steps

Feedback

Was this page helpful?

What type of feedback are you giving?

What would you like us to know?

+Capture screenshot

Can we reach out to you?