Skip to content

Bin operations

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

This page describes bin operations that can be executed by the operate command. Each bin operation works on a specified bin of the target record.

Overview

Aerospike records are made up of metadata and one or more bins containing a supported data types. Nested Lists and Maps, also called collection data types (or CDTs), may be combined to implement a document as a complex data structure.

operate

Acquires a record lock and executes multiple bin operations atomically and in isolation as a single record command. Operations execute sequentially against an in-memory copy of the record. Operations include bin read and write operations, and the operation API of the data types present in the record.

The read side of operate is one form of projection: you can return full bins or the results of read-only operations and expressions. The same bin projection and operation projection model applies to batched operate and, on Database 8.1.2 and later, to foreground queries.

An operate list can also carry operation expressions, which compute a value from the record rather than acting on one named bin. A read expression returns that value under a name that exists only in the response, leaving the record unchanged; a write expression persists it to a bin. For how the two surfaces relate and when to reach for each, see Operations and expressions.

One of the arguments to the operate method is an ordered list of bin operations to execute. The syntax used by Aerospike clients varies by programming language. Unlike a record get operation, which returns an Aerospike record, operate returns output from each sub-operation per bin. The list of operations executes in an “all or nothing” fashion, unless the operation has an explicit NO_FAIL instruction for the server to skip and continue with the next operation. Without it, any failure results in the in-memory copy of the record being discarded and the operate command ends with an error sent back to the client.

The following is the comprehensive list of bin operations that can be part of an operate command.

Data TypeBin operationDescription
Allop_putUpsert (create or update) a bin. Also called write.
Allop_getRead a bin. Also called read.
Allop_touchIncrease the generation counter for a record.
Allop_deleteRemove a record from the database. Generates a tombstone when you use the durable delete policy.
Integer
Float
op_addAdd (or subtract) a value. Used to implement counters. Also called increment.
ListFor a list of all List Operations, see Collection Data Types: Lists.
MapFor a list of all Map Operations, see Collection Data Types: Maps.
Blob/BytesFor a list of all Blob/Bytes operations, see Data Types: Blob/Bytes.
HLLFor a list of all HyperLogLog Operations, see Data Types: HyperLogLog.
StringFor a list of all Unicode-aware string read, modify, and conversion operations, see Data Types: String.
GeoFor a list of all Geospatial Operations, see Data Types: Geospatial.

Filtering

An operate command, batched operate commands, and a query can be conditionally applied, based on the result of a record filter expression. If the filter expression evaluates to true, the command will proceed.

How operate executes

When a client sends an operate command, the server loads the target record from storage into an in-memory copy and acquires the record lock. Every operation in the list then executes sequentially against this copy.

Write operations (put, add, CDT remove_by_*, write expressions, and others) mutate the in-memory copy. Read operations (get, CDT reads, read expressions) observe the copy’s current state, including mutations made by earlier operations in the same list.

After all operations complete:

  • If the list contained any write operation, the modified copy is persisted back to storage and replicated.
  • If the list contained only read operations, the results are returned to the client, the in-memory copy is discarded, and nothing is written to storage.

A mixed list of reads and writes is common for single-record and batched operate commands. Reads see the effect of preceding writes, and the final mutated state is what gets persisted.

Execution trace

Consider a record that starts in storage as:

{"name": "J. Smith", "visits": 1, "status": "active"}

The following four-operation list mixes writes, a bin delete, and reads:

StepOperationIn-memory state afterReturned to client
—(loaded from storage){name: "J. Smith", visits: 1, status: "active"}—
1add("visits", 1){name: "J. Smith", visits: 2, status: "active"}—
2get("visits")(unchanged)visits: 2
3put("status", NIL){name: "J. Smith", visits: 2}—
4get("name")(unchanged)name: "J. Smith"

Persisted to storage: {name: "J. Smith", visits: 2} and the status bin is gone because writing NIL deletes a bin.

Returned to the client: {visits: 2, name: "J. Smith"}, output for the two read operations.

Key takeaways:

  • Step 2 reads visits after step 1 incremented it, so it sees 2.
  • Step 3 deletes the status bin by writing NIL. Any later read of status would see it absent.
  • Step 4 reads name, which no operation in the list touched, so it sees the value loaded from storage.
Session session = cluster.createSession(Behavior.DEFAULT);
DataSet demo = DataSet.of("test", "demo");
session.upsert(demo.id("trace-example"))
.bin("name").setTo("J. Smith")
.bin("visits").setTo(1)
.bin("status").setTo("active")
.execute();
// The SDK returns one result per operation, read by position.
try (RecordStream rs = session.upsert(demo.id("trace-example"))
.bin("visits").add(1) // op 0 — a write, no result
.bin("visits").get() // op 1
.bin("status").remove() // op 2 — a write, no result
.bin("name").get() // op 3
.execute()) {
Record record = rs.getFirstRecord();
System.out.println(record.operationResult(1).getLong()); // 2
System.out.println(record.operationResult(3).getString()); // J. Smith
}

Code example of the operate command

The following example combines read and update operations on the same record into one command.
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.RecordStream;
import com.aerospike.client.sdk.Session;
import com.aerospike.client.sdk.policy.Behavior;
try (Cluster cluster = new ClusterDefinition("127.0.0.1", 3000).connect()) {
Session session = cluster.createSession(Behavior.DEFAULT);
DataSet demo = DataSet.of("test", "demo");
// Create a record with two bins
session.upsert(demo.id("op-example"))
.bin("name").setTo("J. Smith")
.bin("visits").setTo(1)
.execute();
// Combine multiple operations in one atomic command
try (RecordStream rs = session.upsert(demo.id("op-example"))
.bin("visits").add(1) // op 0 — a write, no result
.bin("visits").get() // op 1
.bin("name").get() // op 2
.execute()) {
Record record = rs.getFirstRecord();
System.out.format("visits: %s%n", record.operationResult(1).getLong());
System.out.format("name: %s%n", record.operationResult(2).getString());
// visits: 2
// name: J. Smith
}
}

Usage notes

All read and write operations on records accept policy parameters: Max Retries and Total Timeout.

Write commands take an optional time to live (TTL) parameter which specifies how long the record can live before Aerospike automatically expires it and removes it from the primary index. For details on the interaction between TTL and eviction, see Managing storage capacity.

A transaction’s constituent operations may accept or require additional policy parameters. For additional details about those parameters, refer to the API reference for the client and operation you are using.

Server responses

By default, only read operations return results. In the example above, the three operations produce two results — one per read — grouped by bin name:

{visits: 2, name: "J. Smith"}

The add write executes but does not appear in the output.

To include every operation in the result, enable the respond-all-ops setting on the write policy. A bin that more than one operation touched then returns a list with one entry per operation — null for a write that has no return value — while a bin touched by a single operation returns that operation’s value directly:

{visits: [null, 2], name: "J. Smith"}
WritePolicy writePolicy = new WritePolicy();
writePolicy.respondAllOps = true;

Legacy append and prepend

op_append and op_prepend are the original single-value modify operations. They work on both string and blob bins, take no policy or context argument, and remain supported.

For strings they are superseded by append and prepend, which are Unicode-aware and accept a string policy and a context path to a string nested inside a List or Map bin.

References

See these topics for language-specific examples: