Skip to content

Bin operations

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.

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.
Stringop_append
op_prepend
Modify a string.
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/Byte Operations, see Data Types: Blob/Bytes.
HLLFor a list of all HyperLogLog Operations, see Data Types: HyperLogLog.
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, append, 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 five-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
3append("name", " Jr."){name: "J. Smith Jr.", visits: 2, status: "active"}
4put("status", NIL){name: "J. Smith Jr.", visits: 2}
5get("name")(unchanged)name: "J. Smith Jr."

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

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

Key takeaways:

  • Step 2 reads visits after step 1 incremented it, so it sees 2.
  • Step 4 deletes the status bin by writing NIL. Any later read of status would see it absent.
  • Step 5 reads name after step 3 appended to it, so it sees "J. Smith Jr.".
Key key = new Key("test", "demo", "trace-example");
client.put(null, key,
new Bin("name", "J. Smith"),
new Bin("visits", 1),
new Bin("status", "active"));
Record record = client.operate(null, key,
Operation.add(new Bin("visits", 1)),
Operation.get("visits"),
Operation.append(new Bin("name", " Jr.")),
Operation.put(Bin.asNull("status")),
Operation.get("name"));
System.out.println(record.bins);
// {visits=2, name=J. Smith Jr.}

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.AerospikeClient;
import com.aerospike.client.Bin;
import com.aerospike.client.Key;
import com.aerospike.client.Record;
import com.aerospike.client.Operation;
AerospikeClient client = new AerospikeClient("127.0.0.1", 3000);
Key key = new Key("test", "demo", "op-example");
// Create a record with two bins
client.put(null, key,
new Bin("name", "J. Smith"),
new Bin("visits", 1));
// Combine multiple operations in one atomic command
Record record = client.operate(null, key,
Operation.add(new Bin("visits", 1)),
Operation.append(new Bin("name", " Jr.")),
Operation.get("visits"),
Operation.get("name"));
System.out.format("visits: %s%n", record.bins.get("visits"));
System.out.format("name: %s%n", record.bins.get("name"));
// visits: 2
// name: J. Smith Jr.
client.close();

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 four operations produce two results — one per read — grouped by bin name:

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

The add and append writes execute but do not appear in the output.

To include every operation in the result, enable the respond-all-ops setting on the write policy. With respond-all-ops enabled, each bin returns a list with one entry per operation — null for writes that have no return value:

{visits: [null, 2], name: [null, "J. Smith Jr."]}
ClientPolicy clientPolicy = new ClientPolicy();
clientPolicy.writePolicyDefault.respondAllOps = true;

References

See these topics for language-specific examples:

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?