---
title: "Secondary index"
description: "Guide to creating, dropping, and querying secondary indexes using the Aerospike Rust client."
---

# Secondary index

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

The Aerospike Rust client allows you to create and delete secondary indexes from the database.

## Creating a Secondary Index

To create a secondary index, invoke `Client.create_index()`. Secondary indexes are created asynchronously, so the method returns before the secondary index propagates to the cluster.

The following example creates an index _idx\_foo\_bar\_baz_. The index is in namespace _foo_ within set _bar_ and bin _baz_:

```rust
pub fn create_index(&self,

                    policy: &WritePolicy,

                    namespace: &str,

                    set_name: &str,

                    bin_name: &str,

                    index_name: &str,

                    index_type: IndexType)

                    -> Result<()>;
```

```rust
match client.create_index(&WritePolicy::default(), "foo", "bar", "baz",

    "idx_foo_bar_baz", IndexType::Numeric) {

    Err(err) => println!("Failed to create index: {}", err),

    _ => {}

}
```

Secondary indexes can only be created once on the server as a combination of namespace, set, and bin name with either integer or string data types. For example, if you define a secondary index to index bin _x_ that contains integer values, then only records containing bins named _x_ with integer values are indexed. Other records with a bin named _x_ that contain non-integer values are not indexed.

When an index management call is made to any node in the Aerospike Server cluster, the information automatically propagates to the remaining nodes.

## Removing a Secondary Index

To remove a secondary index using `Client.drop_index()`:

```rust
pub fn drop_index(&self,

                  policy: &WritePolicy,

                  namespace: &str,

                  set_name: &str,

                  index_name: &str)

                  -> Result<()>;
```

## Defining the Query

Use `query::Statement` to define a query.

First, create an instance of `Statement` by specifying the namespace _foo_ and set _bar_ to query. Optionally, you can specify a list of bin names to restrict which record bins are returned by the query.

```rust
use aerospike::Statement;

let mut stmt = Statement::new("foo", "bar", Some(&vec!["name", "age"]));
```

::: note
Namespace is required when querying using secondary indexes; however, sets are optional, depending on the secondary index.
:::

### Applying Filters

To query a secondary index, specify a filter on the query. It appears that multiple filters are allowed, but the server currently restricts queries to a single filter.

Filters are creating using the macros defined in the `aerospike.query` module. The following filters are currently supported:

-   `as_eq!`: Create equality filter for queries; supports integer and string values.
-   `as_range!`: Create range filter for queries; supports integer values.
-   `as_contains!`: Create contains number filter for queries on a collection index.
-   `as_contains_range!`: Create contains range filter for queries on a collection index.
-   `as_within_region!`: Create geospatial “points within region” filter for queries.
-   `as_within_radius!`: Create geospatial “points within radius” filter for queries.
-   `as_regions_containing_point!`: Create geospatial “regions containing point” filter for queries.

This example uses a numeric index on bin _baz_ in namespace _foo_ within set _bar_ to find all records using a filter with the range 0 to 100 inclusive:

```rust
stmt.add_filter(as_range!("baz", 0, 100));
```

::: note
Filters are optional. If not specified, the scan runs over the entire namespace and/or set.
:::

## Executing the Query

To execute the query, invoke `Client.query`:

```rust
pub fn query(&self,

                         policy: &QueryPolicy,

                         statement: Statement)

                         -> Result<Arc<Recordset>> {
```

Where,

-   `policy`: Query behavior definition.
-   `statement`: Query to execute.

`RecordSet` allows you to iterate over the results of the query.

To execute the query and iterate over the results:

```rust
match client.query(&QueryPolicy::default(), stmt) {

    Ok(records) => {

        for record in &*records {

            // .. process record

        }

    },

    Err(err) => println!("Error fetching record: {}", err),

}
```