Skip to content

Map indexes and querying

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

Overview

This page describes how to create a secondary index on bins where the data type is a map. You can index either map key or map value.

Indexing on Map elements

  • Similar to basic indexing, the indexable map data types are numeric, string, and GeoJSON.
  • You can index a Map at any depth. Prior to Database 6.1.0, map indexing was only on the top-level element, not nested elements.
  • When creating index, specify explicitly that map bins should be indexed, and what data type to index on.
  • When querying, specify that query should be applied on a CDT data type.
  • Similar to basic querying, equality, range for numeric and string data type, points-within-region, and region-containing-points for GeoJSON data type are supported.

Examples

The following example uses asadm to create an index with source type mapkeys and a String data type:

Terminal window
Admin+> manage sindex create string foo_mapkey_idx in mapkeys ns test set demo bin foo

The following example uses asadm to create an index with source type mapvalues with a Numeric data type:

Admin+> manage sindex create numeric foo_mapval_idx in mapvalues ns test set demo bin foo

Use show sindex to confirm the indexes were created successfully.

Terminal window
Admin+> show sindex
~~~~~~~~~~~~~~~~~~~Secondary Indexes (2026-04-08 16:01:35 UTC)~~~~~~~~~~~~~~~~~~~
Index Name|Namespace| Set|Bin| Bin| Index|State
| | | | Type| Type|
foo_mapkey_idx|test |demo|foo|string |mapkeys |RW
foo_mapval_idx|test |demo|foo|numeric|mapvalues|RW
Number of rows: 2

Elements of the indexed map are type checked, so a record whose foo bin contains { a:1, b:"2", c:3, d:[4], e:5, 666:"zzz" } results in the following indexing:

Index OnKey TypeIndex TypeEligible Secondary Index Key
foostringMAPKEYSa, b, c, d, e
foonumericMAPVALUES1, 3, 5

Map index queries

This example inserts records with a foo map bin containing mixed key-value types, then queries by map key and map value using the indexes created above.

Insert data

Key key1 = new Key("test", "demo", "u1");
Map<String, Object> cart1 = new HashMap<>();
cart1.put("a", 1);
cart1.put("b", "2");
cart1.put("c", 3);
client.put(null, key1,
new Bin("username", "Bob Roberts"),
new Bin("foo", cart1));
Key key2 = new Key("test", "demo", "u2");
Map<String, Object> cart2 = new HashMap<>();
cart2.put("c", 3);
cart2.put("e", 5);
client.put(null, key2,
new Bin("username", "rocketbob"),
new Bin("foo", cart2));
Key key3 = new Key("test", "demo", "u3");
Map<String, Object> cart3 = new HashMap<>();
cart3.put("x", new HashMap<>(Map.of("z", 26)));
cart3.put("y", "yyy");
client.put(null, key3,
new Bin("username", "samunwise"),
new Bin("foo", cart3));

Query by map value (numeric equality)

Query foo_mapval_idx for records where the foo map contains a value equal to 1. Only records with a matching numeric value are returned — b: "2" is a string, not a numeric, so it does not match.

Statement stmt = new Statement();
stmt.setNamespace("test");
stmt.setSetName("demo");
stmt.setFilter(Filter.contains("foo", IndexCollectionType.MAPVALUES, 1));
RecordSet rs = client.query(null, stmt);
// Returns: {username: "Bob Roberts", foo: {a: 1, b: "2", c: 3}}

Query by map value (numeric equality — multiple matches)

Query for records where the foo map contains a value equal to 3. Both u1 (c: 3) and u2 (c: 3) match.

Statement stmt = new Statement();
stmt.setNamespace("test");
stmt.setSetName("demo");
stmt.setFilter(Filter.contains("foo", IndexCollectionType.MAPVALUES, 3));
RecordSet rs = client.query(null, stmt);
// Returns: Bob Roberts, rocketbob

Query by map value (numeric range)

Query foo_mapval_idx for records where the foo map contains any numeric value in the range [1, 5]. A record is returned once for each matching value in its map.

Statement stmt = new Statement();
stmt.setNamespace("test");
stmt.setSetName("demo");
stmt.setFilter(Filter.range("foo", IndexCollectionType.MAPVALUES, 1, 5));
RecordSet rs = client.query(null, stmt);
// Returns: Bob Roberts (twice: a=1, c=3), rocketbob (twice: c=3, e=5)

Query by map key (string equality)

Query foo_mapkey_idx for records where the foo map contains the key "y".

Statement stmt = new Statement();
stmt.setNamespace("test");
stmt.setSetName("demo");
stmt.setFilter(Filter.contains("foo", IndexCollectionType.MAPKEYS, "y"));
RecordSet rs = client.query(null, stmt);
// Returns: samunwise

Query by map key (multiple matches)

Query for records where the foo map contains the key "c". Both u1 and u2 have a "c" key.

Statement stmt = new Statement();
stmt.setNamespace("test");
stmt.setSetName("demo");
stmt.setFilter(Filter.contains("foo", IndexCollectionType.MAPKEYS, "c"));
RecordSet rs = client.query(null, stmt);
// Returns: Bob Roberts, rocketbob

Query by map key (no match)

Query for a key that does not exist in any record’s map. The index for "z" exists only as a nested key inside the "x" sub-map — top-level MAPKEYS indexing does not reach nested keys.

Statement stmt = new Statement();
stmt.setNamespace("test");
stmt.setSetName("demo");
stmt.setFilter(Filter.contains("foo", IndexCollectionType.MAPKEYS, "z"));
RecordSet rs = client.query(null, stmt);
// Returns: 0 records

Known limitations

  • When using range queries on maps, records can be returned multiple times if the map contains multiple values that fall within the range.