Aerospike.operate/4 executes a list of server-side operations against one
record. Use it for atomic primitive updates, complex data type operations,
expression operations, bit operations, HyperLogLog operations, and readbacks.
Primitive Operations
Primitive operation builders live in Aerospike.Op.
key = Aerospike.key("test", "sessions", "session:1")
{:ok, _metadata} =
Aerospike.put(:aerospike, key, %{
"visits" => 1,
"status" => "new"
})
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.add("visits", 1),
Aerospike.Op.put("status", "active"),
Aerospike.Op.get("visits")
])
record.bins["visits"]List Operations
List operations live in Aerospike.Op.List. Selector operations can choose
return shapes with return-type helpers.
key = Aerospike.key("test", "sessions", "session:events")
{:ok, _metadata} =
Aerospike.put(:aerospike, key, %{"events" => ["created"]})
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.List.append("events", "opened"),
Aerospike.Op.List.size("events")
])
record.bins["events"]Selector helpers can address list entries by index, rank, or value. Index is
position in the list. Rank is position in value order, so -1 means the
highest-ranked value. return_type: controls whether the server returns
values, indexes, ranks, counts, or an existence flag.
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.List.get_by_index("events", 0,
return_type: :value
),
Aerospike.Op.List.get_by_rank("events", -1,
return_type: :value
),
Aerospike.Op.List.get_by_value("events", "opened",
return_type: :exists
)
])List write policies use mnemonic order and flag values. Defaults are the
safest choice; set policy values only when your application needs ordered-list
or write-flag behavior. Advanced compatibility callers can still pass integer
values, including {:raw, integer} for unnamed server values.
Aerospike.Op.List.append("events", "clicked", policy: [order: :ordered, flags: :add_unique])Map Operations
Map operations live in Aerospike.Op.Map.
key = Aerospike.key("test", "profiles", "user:stats")
{:ok, _metadata} =
Aerospike.put(:aerospike, key, %{"stats" => %{"views" => 1}})
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.Map.increment("stats", "views", 1),
Aerospike.Op.Map.put("stats", "updated_by", "worker-1"),
Aerospike.Op.Map.get_by_key("stats", "views",
return_type: :value
)
])
record.bins["stats"]Map selectors can return keys, values, key/value pairs, indexes, ranks, counts,
or existence flags. Key selectors default to keys, value/rank selectors default
to values or key/value pairs depending on the operation; pass return_type:
when the desired shape matters.
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.Map.get_by_key("stats", "views",
return_type: :value
),
Aerospike.Op.Map.get_by_rank("stats", -1,
return_type: :key_value
),
Aerospike.Op.Map.get_by_value("stats", 1,
return_type: :key
)
])
record.bins["stats"]Map write policies use mnemonic order and flag values. :order controls map
ordering and :flags applies write flags when the operation supports them.
Advanced compatibility callers can still pass integer values, including
{:raw, integer} for unnamed server values.
Aerospike.Op.Map.put_items("stats", %{"likes" => 2},
policy: [order: :key_ordered, flags: :update_only]
)Nested CDT Paths
Nested CDT operations use Aerospike.Ctx path steps through the :ctx option.
key = Aerospike.key("test", "profiles", "user:nested")
{:ok, _metadata} =
Aerospike.put(:aerospike, key, %{
"profile" => %{"events" => []}
})
{:ok, _record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.List.append("profile", "signed-in",
ctx: [Aerospike.Ctx.map_key("events")]
)
])Context paths can move through maps and lists by key, value, index, or rank. The operation bin is the top-level CDT bin; each context step navigates inside that value before the operation runs.
key = Aerospike.key("test", "profiles", "user:nested-scores")
{:ok, _metadata} =
Aerospike.put(:aerospike, key, %{
"profile" => %{
"teams" => [
%{"name" => "red", "scores" => [10, 20]},
%{"name" => "blue", "scores" => [15]}
]
}
})
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.List.append("profile", 25,
ctx: [
Aerospike.Ctx.map_key("teams"),
Aerospike.Ctx.list_index(0),
Aerospike.Ctx.map_key("scores")
]
),
Aerospike.Op.List.get_by_rank("profile", -1,
ctx: [
Aerospike.Ctx.map_key("teams"),
Aerospike.Ctx.list_index(0),
Aerospike.Ctx.map_key("scores")
],
return_type: :value
)
])
record.bins["profile"]See Aerospike.Op.List, Aerospike.Op.Map, and Aerospike.Ctx for the full
operation reference.
Bit Operations
Bit operations require Aerospike blob bins. Plain Elixir binaries are encoded
as strings by this client, so seed bit bins with {:blob, binary}.
key = Aerospike.key("test", "profiles", "user:flags")
{:ok, _metadata} =
Aerospike.put(:aerospike, key, %{"flags" => {:blob, <<0>>}})
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.Bit.set("flags", 0, 8, <<0b1010_0000>>),
Aerospike.Op.Bit.count("flags", 0, 8)
])
record.bins["flags"]HyperLogLog Operations
HyperLogLog operations live in Aerospike.Op.HLL and require server support
for HLL bins.
key = Aerospike.key("test", "profiles", "visitors")
{:ok, _metadata} = Aerospike.put(:aerospike, key, %{"seed" => 0})
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.HLL.init("visitors", 14, 0),
Aerospike.Op.HLL.add("visitors", ["ada", "grace"], 14, 0),
Aerospike.Op.HLL.get_count("visitors")
])
record.bins["visitors"]Expression Operations
Expression operate helpers live in Aerospike.Op.Exp and return or write
server-side expression values.
{:ok, record} =
Aerospike.operate(:aerospike, key, [
Aerospike.Op.Exp.read("projected", Aerospike.Exp.int_bin("score")),
Aerospike.Op.Exp.write("score_copy", Aerospike.Exp.int_bin("score"))
])
record.bins["projected"]Geo Values And Queries
Use Aerospike.Geo typed values for GeoJSON bins. Geo secondary-index queries
use Aerospike.Filter.geo_within/2 or Aerospike.Filter.geo_contains/2.
key = Aerospike.key("test", "places", "pdx")
point = Aerospike.Geo.point(-122.6765, 45.5231)
{:ok, _metadata} = Aerospike.put(:aerospike, key, %{"loc" => point})
{:ok, task} =
Aerospike.create_index(:aerospike, "test", "places",
bin: "loc",
name: "places_loc_geo_idx",
type: :geo2dsphere
)
:ok = Aerospike.IndexTask.wait(task)
region = Aerospike.Geo.circle(-122.6765, 45.5231, 10_000.0)
query =
Aerospike.Query.new("test", "places")
|> Aerospike.Query.where(Aerospike.Filter.geo_within("loc", region))
|> Aerospike.Query.max_records(100)
{:ok, records} = Aerospike.query_all(:aerospike, query)Geo filters require matching secondary indexes. query_all/3 and
query_page/3 require query.max_records.