---
title: "Map operations"
description: "Guide to the Rust client's operations::maps builders for server-side map CDT operations with Client::operate()."
---

# Map operations

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

A _map bin_ stores key-value pairs. Keys are strings, integers, or byte arrays, and values can be any supported data type. The server’s map [collection data type (CDT)](https://aerospike.com/docs/develop/data-types/collections) operations change, read, and remove individual entries in a single round trip, without the client reading the whole bin first.

[`Client::put`](https://docs.rs/aerospike/latest/aerospike/struct.Client.html#method.put) always replaces the full bin value. To change entries of a map bin that already exists, use the `aerospike::operations::maps` builders with [`Client::operate()`](https://aerospike.com/docs/develop/client/rust/usage/atomic/multi).

## Setup

```rust
use aerospike::operations::maps;

use aerospike::{

    as_bin, as_key, as_map, as_val, Bins, Client, ClientPolicy, MapPolicy, MapReturnType,

    ReadPolicy, Value, WritePolicy,

};

let client = Client::new(&ClientPolicy::default(), &"127.0.0.1:3000").await?;

let policy = MapPolicy::default();
```

> 📖 **API reference**: [`Client::new`](https://docs.rs/aerospike/latest/aerospike/struct.Client.html#method.new) | [`operations::maps`](https://docs.rs/aerospike/latest/aerospike/operations/maps/index.html) | [`MapPolicy`](https://docs.rs/aerospike/latest/aerospike/operations/maps/struct.MapPolicy.html)

The `as_map!` and `as_list!` macros expand to `as_val!`, so import `as_val` too.

## Write a map bin

To write a map as the whole value of a bin, build it with `as_map!` and pass it to `put()`:

```rust
let key = as_key!("test", "stats", "page:1");

let bin = as_bin!("daily", as_map!("2026-10-01" => 5));

client.put(&WritePolicy::default(), &key, &[bin]).await?;
```

> 📖 **API reference**: [`as_map!`](https://docs.rs/aerospike/latest/aerospike/macro.as_map.html) | [`Value::HashMap`](https://docs.rs/aerospike/latest/aerospike/enum.Value.html#variant.HashMap)

## Increment counters in a map

`maps::increment_value(&policy, bin, key, amount)` adds `amount` to the number stored under `key`. If the key doesn’t exist yet, the server creates it and sets it to `amount`. No read is required first.

Pass several increments in one `operate()` call to change several keys in a single round trip. `record.results` holds one answer per operation, in order. Each answer is the key’s new value:

```rust
let key = as_key!("test", "stats", "page:1");

let ops = vec![

    maps::increment_value(&policy, "daily", Value::from("2026-10-01"), Value::from(1)),

    maps::increment_value(&policy, "daily", Value::from("2026-10-02"), Value::from(1)),

];

let record = client.operate(&WritePolicy::default(), &key, &ops).await?;

println!("{:?}", record.results);
```

> 📖 **API reference**: [`operations::maps::increment_value`](https://docs.rs/aerospike/latest/aerospike/operations/maps/fn.increment_value.html) | [`Client::operate`](https://docs.rs/aerospike/latest/aerospike/struct.Client.html#method.operate)

## Read a map back

A `get` returns a map bin as a `Value::OrderedMap`, which holds the entries in key order. Match on it to read the entries. Key-ordered maps (K-ordered on the server) arrive as `Value::SortedMap` instead:

```rust
let record = client.get(&ReadPolicy::default(), &key, Bins::All).await?;

if let Some(Value::OrderedMap(daily)) = record.bins.get("daily") {

    for (date, views) in daily {

        println!("{date}: {views}");

    }

}
```

> 📖 **API reference**: [`Value::OrderedMap`](https://docs.rs/aerospike/latest/aerospike/enum.Value.html#variant.OrderedMap)

## Select entries by rank

The _rank_ of an entry is its position when the server sorts the entries by value. Rank `0` is the entry with the lowest value. A negative rank counts from the highest value, so `-1` is the highest.

`maps::get_by_rank_range(bin, rank, count, return_type)` selects `count` entries that start at `rank`. To read the three highest-scoring players of a leaderboard, start at rank `-3`:

```rust
let key = as_key!("test", "games", "board:1");

let scores = as_map!("ann" => 120, "bob" => 340, "cat" => 90, "dan" => 500, "eve" => 275);

client.put(&WritePolicy::default(), &key, &[as_bin!("scores", scores)]).await?;

let ops = vec![maps::get_by_rank_range("scores", -3, 3, MapReturnType::KeyValue)];

let record = client.operate(&WritePolicy::default(), &key, &ops).await?;

// The entries come back from the lowest of the three scores to the highest.

if let Some(Value::KeyValueList(entries)) = record.operation_result(0) {

    for (player, score) in entries.iter().rev() {

        println!("{player}: {score}");

    }

}
```

> 📖 **API reference**: [`operations::maps::get_by_rank_range`](https://docs.rs/aerospike/latest/aerospike/operations/maps/fn.get_by_rank_range.html) | [`Value::KeyValueList`](https://docs.rs/aerospike/latest/aerospike/enum.Value.html#variant.KeyValueList)

`MapReturnType::KeyValue` returns the selected entries as a `Value::KeyValueList`, a list of `(key, value)` pairs in rank order. The server selects the entries, so the program doesn’t fetch and sort the whole map.

## Remove a key and return its value

`maps::remove_by_key(bin, key, return_type)` removes one entry from the map. The return type selects what the server sends back about the removed entry. To remove a key and get its value in the same call, use `MapReturnType::Value`:

```rust
let key = as_key!("test", "settings", "user:1");

let prefs = as_map!("lang" => "en", "theme" => "dark", "beta" => true);

client.put(&WritePolicy::default(), &key, &[as_bin!("prefs", prefs)]).await?;

let ops = vec![maps::remove_by_key("prefs", Value::from("beta"), MapReturnType::Value)];

let record = client.operate(&WritePolicy::default(), &key, &ops).await?;

println!("removed: {:?}", record.operation_result(0));
```

> 📖 **API reference**: [`operations::maps::remove_by_key`](https://docs.rs/aerospike/latest/aerospike/operations/maps/fn.remove_by_key.html)

The other entries of the map stay as they were. The server updates the entry in place, and the client sends one map operation instead of reading and writing the whole bin.

## Choose what an operation returns

Map read and remove operations take a `MapReturnType` that selects what the server returns for the entries the operation selected:

| `MapReturnType` | What the server returns |
| --- | --- |
| `None` | Nothing. The result is `Value::Nil`. |
| `Count` | The number of entries selected. |
| `Key` | The key of a single entry, or a list of keys for a range. |
| `Value` | The value of a single entry, or a list of values for a range. |
| `KeyValue` | The entries as key-value pairs. |
| `Index` | The key-order position of the entry, where `0` is the first key. |
| `ReverseIndex` | The position in reverse key order, where `0` is the last key. |
| `Rank` | The rank of the entry, where `0` is the lowest value. |
| `ReverseRank` | The rank in reverse value order, where `0` is the highest value. |
| `Exists` | `true` if the operation selected at least one entry. |

> 📖 **API reference**: [`MapReturnType`](https://docs.rs/aerospike/latest/aerospike/enum.MapReturnType.html)

To invert a selection, pass `InvertedMapReturn(MapReturnType::Key)` from `aerospike::operations::maps` instead of the plain return type.

For nested-path navigation with `CdtContext`, see the [`operations::maps`](https://docs.rs/aerospike/latest/aerospike/operations/maps/index.html) API reference.

## Next steps

-   [List operations](https://aerospike.com/docs/develop/client/rust/usage/cdt/lists): Change, read, and remove list elements on the server.
-   [Bin operations](https://aerospike.com/docs/develop/client/rust/usage/atomic/multi): Combine several operations in one `operate()` call.