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) }}