Transaction operations
Aerospike records contain one or more bins of potentially different data types. Nested Lists and Maps, also called collection data types (or CDTs) may be combined to implement a complex data structure as a document. To service these potentially-complex documents of data, every Aerospike client provides the following method:
operate
Combines multiple operations on a single record into a transaction. Operations include the bin read and write operations, and any operation on a data type, which is stored in a bin. Examples are add on integer bins, HLL operations on HyperLogLog bins, bitwise operations on Blob (Bytes) bins, or the large API of operations on list and map bins.
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. This is useful to confirm transaction processing and to troubleshoot logic that results in unexpected transaction success or failures.
Each operate
call results in an ACID-compliant transaction consisting of one or more ordered bin operations on the record. This operation is a single atomic transaction that is processed by Aerospike under a record lock with isolation and durability. By comparison, every record operation results in an atomic transaction consisting of a single operation.
The following is the comprehensive list of bin operations that can be part of a transaction using operate. The table below contains either the operations or a link to the comprehensive list of operations for each data type.
Data Type | Operation | Description |
---|---|---|
All | op_put | Upsert (create or update) a bin. Also called write . |
All | op_get | Read a bin. Also called read . |
All | op_touch | Increase the generation counter for a record. |
All | op_delete | Remove a record from the database. Generates a tombstone when you use the durable delete policy. |
Integer Float | op_add | Add (or subtract) a value. Used to implement counters. Also called increment . |
String | op_append op_prepend | Modify a string. |
List | For a list of all List Operations, see Collection Data Types: Lists. | |
Map | For a list of all Map Operations, see Collection Data Types: Maps. | |
Blob/ Bytes | For a list of all Blob/Byte Operations, see Data Types: Blob/Bytes. | |
HLL | For a list of all HyperLogLog Operations, see Data Types: HyperLogLog. | |
Geo | For a list of all Geospatial Operations, see Data Types: Geospatial. |
As of Aerospike version 5.6, Aerospike operation expressions can be applied to any transaction operation mentioned above.
Filtering Transactions
A transaction can be conditionally applied, based on the result of a filter expression. If the filter expression evaluates to true, the transaction will execute. Older versions starting with Aerospike 4.7 can apply a predicate filter to the transaction.
Support for predicate filters is planned for removal in Aerospike 5.8, so We recommend that you filter expressions (added in version 5.2) be used in their place.
Code example of a transaction operation
The following examples perform read and update bin operations on a record. The syntax differs per Aerospike client, based on the needs of the operating system.
- Python
- Java
# The following is the primary key of a record
#
# key = (namespace_name, set_name, user_key)
#
# The following is the Aerospike record associated with that key.
#
# bins = {
# 'l': [ "qwertyuiop", 1, bytearray("asd;as[d'as;d", "utf-8") ],
# 'm': { "key": "asd';q;'1';" },
# 'i': 1234,
# 'f': 3.14159265359,
# 's': '!@#@#$QSDAsd;as'
# }
ops = [
operations.increment('i', 1)
operations.read('i')
operations.append('s', 'foobarbaz')
operations.read('s')
]
client.operate(key, ops)
# Expected result:
# i is now 1235
# s is now !@#@#$QSDAsd;asfoobarbaz
import java.util.HashMap;
import java.util.Map;
import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Bin;
import com.aerospike.client.Key;
import com.aerospike.client.Operation;
import com.aerospike.client.Record;
import com.aerospike.client.Value;
import com.aerospike.client.policy.RecordExistsAction;
import com.aerospike.client.policy.WritePolicy;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
AerospikeClient client = new AerospikeClient("localhost", 3000);
// Aerospike namespace, set, and key_id to be used for the Aerospike key
String namespace = "sandbox";
String set = "ufo";
int key_id = 5231;
// Create key
Key key = new Key(namespace, set, key_id);
// Example JSON string
String sighting = "{\"sighting\":{\"occurred\":20200912,\"reported\":20200916,\"posted\":20201105,\"report\":{\"city\":\"Kirkland\",\"duration\":\"~30 minutes\",\"shape\":[\"circle\"],\"state\":\"WA\",\"summary\":\"4 rotating orange lights in the Kingsgate area above the Safeway. Around 9pm the power went out in the Kingsgate area. Four lights were spotted rotating above the local Safeway and surrounding streets. They were rotating fast but staying relatively in the same spots. Also described as orange lights. About thirty minutes later they disappeared. The second they disappeared the power was restored. Later a station of police from Woodinville and Kirkland came to guard the street where it happened. They wouldn't let anyone go past the street, putting out search lights and flare signals so people couldn't drive past Safeway. The police also would not let people walk past to go home.\"},\"location\":\"\\\"{\\\"type\\\":\\\"Point\\\",\\\"coordinates\\\":[-122.1966441,47.69328259]}\\\"\"}}";
// Convert string to Java Map
Map<String, Map<String, Object>> sightingMap = new Gson().fromJson(sighting, new TypeToken<HashMap<String, HashMap<String, Object>>>(){}.getType());
// Create bins from map
Bin[] bins = {
new Bin("occurred", Value.get(sightingMap.get("sighting").get("occurred"))),
new Bin("reported", Value.get(sightingMap.get("sighting").get("reported"))),
new Bin("posted", Value.get(sightingMap.get("sighting").get("posted"))),
new Bin("report", Value.get(sightingMap.get("sighting").get("report"))),
};
// Create write policy
WritePolicy writePolicy = client.copyWritePolicyDefault();
writePolicy.recordExistsAction = RecordExistsAction.UPDATE;
writePolicy.respondAllOps = true;
// Write record
client.put(writePolicy, key, bins);
// Read written record
Record record = client.get(null, key);
if (record != null) {
System.out.printf("Report: %s %nOccurred: %.0f%n", new Gson().toJson(record.getValue("report")), record.getValue("occurred"));
}
else {
System.out.printf("Record with key: %s does not exist%n", key.userKey.toString());
}
// Update data
Map<String, Object> updateMap = Map.of("zip", Integer.valueOf(98105));
Bin[] updateBins = {
new Bin("occurred", Value.get(5D)), // Increment amount
new Bin("report", Value.get(updateMap)) // Updated report payload
};
// Update operations
Operation[] operations = {
Operation.add(updateBins[0]), // Increment
Operation.put(updateBins[1]), // Replace/update
};
// Update record
client.operate(writePolicy, key, operations);
// Read updated record
Record updateRecord = client.get(null, key);
if (updateRecord != null) {
System.out.printf("Report: %s \nOccurred: %.0f%n", new Gson().toJson(updateRecord.getValue("report")), updateRecord.getValue("occurred"));
}
else {
System.out.printf("UpdateRecord with key: %s does not exist%n", key.userKey.toString());
}
Usage notes
All read and write operations on records accept policy parameters: Max Retries and Total Timeout.
Write operations 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 more 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
Some types of write operations do not return results
by default, which can make it difficult to determine the correct result offset.
To ensure that every write operation returns a result, set the
WritePolicy.respondAllOps
field to true
.
ClientPolicy clientPolicy = new ClientPolicy();
clientPolicy.WritePolicyDefault.respondAllOps = true;
References
See these topics for language-specific examples: