Skip to content

Update records

Learn how to update existing records in Aerospike using the Developer SDK. This guide covers updating bins, using operations, conditional updates, and optimistic locking.

Update specific bins

Use update() to modify specific bins in an existing record:

DataSet users = DataSet.of("test", "users");
// Update only the email bin
session.update(users.id("user-1"))
.bin("email").setTo("newemail@example.com")
.execute();
// Update multiple bins
session.update(users.id("user-1"))
.bin("email").setTo("newemail@example.com")
.bin("phone").setTo("+1-555-1234")
.bin("updated_at").setTo(System.currentTimeMillis())
.execute();

See also: Insert vs upsert vs other operations

Increment numbers

Atomically increment numeric values:

// Increment view count by 1
session.update(users.id("user-1"))
.bin("view_count").add(1)
.execute();
// Increment by a larger amount
session.update(users.id("user-1"))
.bin("points").add(100)
.execute();
// Decrement (negative increment)
session.update(users.id("user-1"))
.bin("credits").add(-10)
.execute();
// Multiple increments in one operation
session.update(users.id("user-1"))
.bin("login_count").add(1)
.bin("points").add(5)
.bin("last_login").setTo(System.currentTimeMillis())
.execute();

Read back after incrementing:

try (RecordStream writeResult = session.update(users.id("user-1"))
.bin("view_count").add(1)
.bin("view_count").get()
.execute()) {
Record updated = writeResult.getFirstRecord();
System.out.println("view_count: " + updated.getInt("view_count"));
}

Append to strings

Append text to string bins:

// Append to a log field
session.update(users.id("user-1"))
.bin("activity_log").append("\n2024-01-15: Logged in")
.execute();
// Prepend (add to beginning)
session.update(users.id("user-1"))
.bin("activity_log").prepend("Latest: ")
.execute();

Update list/map bins (CDT)

Collection updates use the bin(...) builder with list/map path methods. This lets you update nested structures without a full read-modify-write cycle.

import com.aerospike.client.sdk.DataSet;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
import com.aerospike.client.sdk.cdt.MapOrder;
DataSet hotels = DataSet.of("test", "hotels");
String key = "hotel:1";
// CD-1 style: set a map entry value.
session.update(hotels.id(key))
.bin("rooms").onMapKey("room1").setTo(150)
.execute();
// CD-2 style: one round-trip with range read + count.
try (RecordStream rs = session.update(hotels.id(key))
.bin("rooms").onMapKeyRange("room1", "room4").getKeysAndValues()
.bin("rooms").onMapKeyRange("room1", "room4").count()
.execute()) {
var rec = rs.getFirstRecord();
List<?> roomData = rec.getList("rooms");
System.out.println("rooms: " + roomData.get(0));
System.out.println("room count: " + roomData.get(1));
// rangeResult = map entries in range, countResult = count
}
// CD-3 style: append to list and read list size in one round-trip.
try (RecordStream rs = session.update(hotels.id(key))
.bin("tags").listAppend("vip")
.bin("tags").listSize()
.execute()) {
// Second result row contains size information.
}
// CD-4 style: nested path update (rooms -> room1 -> rates).
session.update(hotels.id(key))
.bin("rooms").onMapKey("room1", MapOrder.KEY_ORDERED)
.onMapKey("rates").setTo(110)
.execute();

Touch (update metadata only)

“Touch” a record to reset its TTL without changing bin values:

import java.time.Duration;
import com.aerospike.client.sdk.AerospikeException;
// Reset TTL to 30 days from now
try {
session.touch(users.id("user-1"))
.expireRecordAfter(Duration.ofDays(30))
.execute();
} catch (AerospikeException e) {
// If server/namespace TTL prerequisites are not met, you can get "Operation not allowed at this time".
System.err.println("Touch failed: " + e.getMessage());
}

Delete bins

Remove specific bins from a record (without deleting the record):

// Remove the phone bin
session.update(users.id("user-1"))
.bin("phone").remove()
.execute();
// Remove multiple bins
session.update(users.id("user-1"))
.bin("phone").remove()
.bin("fax").remove()
.bin("pager").remove()
.execute();

Conditional update (optimistic locking)

Use generation checks to prevent concurrent update conflicts:

import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
// Read current record
RecordStream readStream = session.query(users.id("user-1")).execute();
Record user = readStream.getFirstRecord();
int currentGeneration = user.generation;
// Update only if generation hasn't changed
try {
session.update(users.id("user-1"))
.bin("email").setTo("newemail@example.com")
.ensureGenerationIs(currentGeneration)
.execute();
System.out.println("Update successful");
} catch (GenerationException e) {
System.out.println("Record was modified by another process");
}

Optimistic locking pattern

import com.aerospike.client.sdk.Record;
import com.aerospike.client.sdk.RecordResult;
import com.aerospike.client.sdk.RecordStream;
public void updateWithRetry(DataSet users, String userId, int maxRetries) {
for (int attempt = 0; attempt < maxRetries; attempt++) {
// Read current state
RecordStream rs = session.query(users.id(userId)).execute();
Record user = rs.getFirstRecord();
int newBalance = user.getInt("balance") + 100;
try {
// Attempt update with generation check
session.update(users.id(userId))
.bin("balance").setTo(newBalance)
.ensureGenerationIs(user.generation)
.execute();
return; // Success
} catch (GenerationException e) {
// Retry on conflict
System.out.println("Conflict, retrying...");
}
}
throw new RuntimeException("Max retries exceeded");
}

Update only if exists

Ensure the record exists before updating:

try {
session.update(users.id("user-1"))
.bin("email").setTo("newemail@example.com")
.execute();
} catch (RecordNotFoundException e) {
System.out.println("Record doesn't exist");
}

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 UpdateRecordsExample {
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 key = "update-example-user";
// Seed data so the example is repeatable.
session.upsert(users)
.bins("name", "login_count", "points")
.id(key).values("Alice Smith", 0, 0)
.execute();
// Simple update
session.update(users.id(key))
.bin("status").setTo("active")
.bin("updated_at").setTo(System.currentTimeMillis())
.execute();
// Increment counters
session.update(users.id(key))
.bin("login_count").add(1)
.bin("points").add(10)
.execute();
// Conditional update with generation check
RecordStream rs = session.query(users.id(key)).execute();
Record user = rs.getFirstRecord();
session.update(users.id(key))
.bin("verified").setTo(true)
.ensureGenerationIs(user.generation)
.execute();
System.out.println("All updates completed!");
}
}
}

API reference summary

MethodDescriptionLink
update()Update an existing record, fails if the record doesn’t existJava · Python
touch()Update metadata/TTL onlyJava · Python
.bin(name).add(delta) / .bin(name).increment_by(delta)Atomically increment a numeric bin
.bin(name).append(text) / .prepend(text)Append or prepend a string bin
.bin(name).remove()Remove a bin
.ensureGenerationIs(gen) / .ensure_generation_is(gen)Conditional update

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?