Skip to content

Document secondary indexes

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

This guide provides practical Go examples for executing secondary index queries on document records in Aerospike. It demonstrates two approaches: indexing a dedicated bin during record insertion and using MAPVALUES indexes to query nested values inside document bins.

Secondary index usage

The following example demonstrates using a secondary index to find a document record. It does the following:

  • Create a document.
  • Add the document to an Aerospike set.
  • Create a secondary index.
  • Query the document using the secondary index.

The example demonstrates two ways of setting up a secondary index. The first approach stores the index target in a dedicated bin at write time. The second approach indexes values inside the document bin with a MAPVALUES index.

Setup

Import the necessary helpers and create a client connection.

import (
"fmt"
"log"
as "github.com/aerospike/aerospike-client-go/v8"
)
client, err := as.NewClient("127.0.0.1", 3000)
if err != nil {
log.Fatal(err)
}
defer client.Close()
namespace := "test"
setName := "table1"

Create a JSON document

Prepare the JSON document to send to Aerospike.

transactions := []map[string]interface{}{
{"txn_id": "1111", "name": "Davis", "item_id": "A1234", "count": 1},
{"txn_id": "2222", "name": "Johnson", "item_id": "B2345", "count": 2},
{"txn_id": "3333", "name": "Johnson", "item_id": "C3456", "count": 2},
{"txn_id": "4444", "name": "Lee", "item_id": "D4567", "count": 3},
}

First approach: write-time indexing

Write each document to Aerospike.

writePolicy := as.NewWritePolicy(0, 0)
writePolicy.SendKey = true
for _, transaction := range transactions {
key, err := as.NewKey(namespace, setName, transaction["txn_id"])
if err != nil {
log.Fatal(err)
}
bins := as.BinMap{
"name": transaction["name"],
"transaction": transaction,
}
if err := client.Put(writePolicy, key, bins); err != nil {
log.Fatalf("Create failed: %v", err)
}
record, err := client.Get(nil, key)
if err != nil {
log.Fatalf("Read failed: %v", err)
}
fmt.Printf("Create succeeded\nKey: %v\nRecord: %v\n", key.Value(), record.Bins)
}

Create a secondary index on a dedicated bin

Create a secondary index on the dedicated name bin and execute a query. This approach stores the index target in its own bin during record insertion.

task, err := client.CreateIndex(nil, namespace, setName, "test_name_idx", "name", as.STRING)
if err != nil {
log.Fatalf("Create index failed: %v", err)
}
<-task.OnComplete()
stmt := as.NewStatement(namespace, setName)
stmt.SetFilter(as.NewEqualFilter("name", "Johnson"))
recordSet, err := client.Query(nil, stmt)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
for res := range recordSet.Results() {
if res.Err != nil {
log.Fatalf("Query result error: %v", res.Err)
}
fmt.Printf("Key: %v | Record: %v\n", res.Record.Key.Value(), res.Record.Bins)
}
recordSet.Close()
if err := client.DropIndex(nil, namespace, setName, "test_name_idx"); err != nil {
log.Fatalf("Drop index failed: %v", err)
}

Second approach: create a MAPVALUES index on the document bin

Create a secondary index on map values in the transaction bin and execute a query. This approach indexes nested values inside the document bin directly.

task, err := client.CreateComplexIndex(
nil, namespace, setName, "test_transaction_idx", "transaction", as.STRING, as.ICT_MAPVALUES)
if err != nil {
log.Fatalf("Create index failed: %v", err)
}
<-task.OnComplete()
stmt := as.NewStatement(namespace, setName)
stmt.SetFilter(as.NewContainsFilter("transaction", as.ICT_MAPVALUES, "Johnson"))
recordSet, err := client.Query(nil, stmt)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
for res := range recordSet.Results() {
if res.Err != nil {
log.Fatalf("Query result error: %v", res.Err)
}
fmt.Printf("Key: %v | Record: %v\n", res.Record.Key.Value(), res.Record.Bins)
}
recordSet.Close()
if err := client.DropIndex(nil, namespace, setName, "test_transaction_idx"); err != nil {
log.Fatalf("Drop index failed: %v", err)
}

Code block: dedicated bin index

Expand this section for a single code block to run the dedicated bin index example.
package main
import (
"fmt"
"log"
as "github.com/aerospike/aerospike-client-go/v8"
)
func main() {
client, err := as.NewClient("127.0.0.1", 3000)
if err != nil {
log.Fatal(err)
}
defer client.Close()
namespace := "test"
setName := "table1"
records := []map[string]interface{}{
{"record_id": "1111", "name": "Davis", "item_id": "A1234", "count": 1},
{"record_id": "2222", "name": "Johnson", "item_id": "B2345", "count": 2},
{"record_id": "3333", "name": "Johnson", "item_id": "C3456", "count": 2},
{"record_id": "4444", "name": "Lee", "item_id": "D4567", "count": 3},
}
writePolicy := as.NewWritePolicy(0, 0)
writePolicy.SendKey = true
for _, record := range records {
key, err := as.NewKey(namespace, setName, record["record_id"])
if err != nil {
log.Fatal(err)
}
bins := as.BinMap{
"name": record["name"],
"transaction": record,
}
if err := client.Put(writePolicy, key, bins); err != nil {
log.Fatalf("Create failed: %v", err)
}
}
task, err := client.CreateIndex(nil, namespace, setName, "test_name_idx", "name", as.STRING)
if err != nil {
log.Fatalf("Create index failed: %v", err)
}
<-task.OnComplete()
stmt := as.NewStatement(namespace, setName)
stmt.SetFilter(as.NewEqualFilter("name", "Johnson"))
recordSet, err := client.Query(nil, stmt)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
for res := range recordSet.Results() {
if res.Err != nil {
log.Fatalf("Query result error: %v", res.Err)
}
fmt.Printf("Key: %v | Record: %v\n", res.Record.Key.Value(), res.Record.Bins)
}
recordSet.Close()
if err := client.DropIndex(nil, namespace, setName, "test_name_idx"); err != nil {
log.Fatalf("Drop index failed: %v", err)
}
}

Code block — MAPVALUES index on document bin

Expand this section for a single code block to run the MAPVALUES index example.
package main
import (
"fmt"
"log"
as "github.com/aerospike/aerospike-client-go/v8"
)
func main() {
client, err := as.NewClient("127.0.0.1", 3000)
if err != nil {
log.Fatal(err)
}
defer client.Close()
namespace := "test"
setName := "table1"
transactions := []map[string]interface{}{
{"txn_id": "1111", "name": "Davis", "item_id": "A1234", "count": 1},
{"txn_id": "2222", "name": "Johnson", "item_id": "B2345", "count": 2},
{"txn_id": "3333", "name": "Johnson", "item_id": "C3456", "count": 2},
{"txn_id": "4444", "name": "Lee", "item_id": "D4567", "count": 3},
}
writePolicy := as.NewWritePolicy(0, 0)
writePolicy.SendKey = true
for _, transaction := range transactions {
key, err := as.NewKey(namespace, setName, transaction["txn_id"])
if err != nil {
log.Fatal(err)
}
bins := as.BinMap{
"name": transaction["name"],
"transaction": transaction,
}
if err := client.Put(writePolicy, key, bins); err != nil {
log.Fatalf("Create failed: %v", err)
}
}
task, err := client.CreateComplexIndex(
nil, namespace, setName, "test_transaction_idx", "transaction", as.STRING, as.ICT_MAPVALUES)
if err != nil {
log.Fatalf("Create index failed: %v", err)
}
<-task.OnComplete()
stmt := as.NewStatement(namespace, setName)
stmt.SetFilter(as.NewContainsFilter("transaction", as.ICT_MAPVALUES, "Johnson"))
recordSet, err := client.Query(nil, stmt)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
for res := range recordSet.Results() {
if res.Err != nil {
log.Fatalf("Query result error: %v", res.Err)
}
fmt.Printf("Key: %v | Record: %v\n", res.Record.Key.Value(), res.Record.Bins)
}
recordSet.Close()
if err := client.DropIndex(nil, namespace, setName, "test_transaction_idx"); err != nil {
log.Fatalf("Drop index failed: %v", err)
}
}
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?