Secondary Indexes
Oxia allows records to be indexed by one or more secondary keys in addition to their primary key. Secondary indexes enable efficient lookups and range queries on alternative key spaces without duplicating data.
Use cases
- Multi-attribute lookups: A record keyed by ID can also be indexed by name, email, or any other attribute.
- Reverse mappings: Create bidirectional lookups without maintaining separate records.
- Alternative sort orders: Query the same data set using different key orderings.
How secondary indexes work
When writing a record, you can attach one or more secondary index entries. Each entry specifies an index name and a secondary key. The secondary key does not need to be unique — multiple records can share the same secondary key within the same index.
When querying with List, RangeScan, or Get, you can specify an index name to search by
secondary keys instead of primary keys. The results still return the primary keys and values of the
matching records.
Using secondary indexes
Writing records with secondary indexes
Go
// Index a user record by email
_, _, err := client.Put(context.Background(), "/users/123",
[]byte(`{"name":"Alice","email":"alice@example.com"}`),
oxia.SecondaryIndex("by-email", "alice@example.com"),
)Querying by secondary index
Use the UseIndex option on Get, List, or RangeScan to query using secondary keys.
Go
// Lookup by secondary index
key, value, version, err := client.Get(context.Background(),
"alice@example.com",
oxia.UseIndex("by-email"),
)
// List all keys in a secondary index range
keys, err := client.List(context.Background(),
"a", "b",
oxia.UseIndex("by-email"),
)
// Range scan using secondary index
ch := client.RangeScan(context.Background(),
"a", "b",
oxia.UseIndex("by-email"),
)
for result := range ch {
fmt.Printf("primary key: %s, value: %s\n", result.Key, string(result.Value))
}Updating secondary indexes
Secondary indexes are updated atomically with the record. When you Put a record with new secondary
index entries, the previous index entries for that record are replaced.
// Update the email index for user 123
_, _, err := client.Put(context.Background(), "/users/123",
[]byte(`{"name":"Alice","email":"newalice@example.com"}`),
oxia.SecondaryIndex("by-email", "newalice@example.com"),
)When a record is deleted, all of its secondary index entries are automatically removed.