<commit_before>---
layout: documentation
title: Using secondary indexes in RethinkDB
active: docs
docs_active: secondary-indexes
permalink: docs/secondary-indexes/javascript/
switcher: true
language : JavaScript 
js: [fancybox]
---

Secondary indexes are data structures that improve the speed of many
read queries at the slight cost of increased storage space and decreased
write performance.

RethinkDB supports different types of secondary indexes:

- __Simple indexes__ based on the value of a single field.
- __Compound indexes__ based on multiple fields.
- __Multi indexes__ based on arrays of values.
- Indexes based on __arbitrary expressions__.

# Using indexes #

## Simple indexes ##

Use simple indexes to efficiently retrieve and order documents by the value of a single field.

### Creation ###

```js
// Create a secondary index on the last_name attribute
r.table("users").indexCreate("last_name").run(conn, callback)
```

```js
// Wait for the index to be ready to use
r.table("users").indexWait("last_name").run(conn, callback)
```

### Querying ###

```js
// Get all users whose last name is "Smith"
r.table("users").getAll("Smith", {index: "last_name"}).run(conn, callback)

// Get all users whose last names are "Smith" or "Lewis"
r.table("users").getAll("Smith", "Lewis", {index: "last_name"}).run(conn, callback)

// Get all users whose last names are between "Smith" and "Wade"
r.table("users").between("Smith", "Wade", {index: "last_name"}).run(conn, callback)

// Efficiently order users by last name using an index
r.table("users").orderBy({index: "last_name"}).run(conn, callback)

// For each blog post, return the post and its author using the last_name index
r.table("posts").eqJoin("author_last_name", r.table("users"), {index: "last_name"}) \
    .zip().run(conn, callback)
```

{% infobox info %}
__Want to learn more about joins in RethinkDB?__ See [how to use joins](/docs/table-joins/)
to query _one to many_ and _many to many_ relations.
{% endinfobox %}

## Compound indexes ##

Use compound indexes to efficiently retrieve documents by multiple fields.

### Creation ###

```js
// Create a compound secondary index based on the first_name and last_name attributes
r.table("users").indexCreate("full_name", [r.row("first_name"), r.row("last_name")]) \
    .run(conn, callback)
```

```js
// Wait for the index to be ready to use
r.table("users").indexWait("full_name").run(conn, callback)
```

### Querying ###

```js
// Get all users whose full name is <NAME>.
r.table("users").getAll(["John", "Smith"], {index: "full_name"}).run(conn, callback)

// Get all users whose full name is between "<NAME>" and "<NAME>"
r.table("users").between(["John", "Smith"], ["Wade", "Welles"], {index: "full_name"}) \
    .run(conn, callback)

// Efficiently order users by first name and last name using an index
r.table("users").orderBy({index: "full_name"}).run(conn, callback)

// For each blog post, return the post and its author using the full_name index
r.table("posts").eqJoin("author_full_name", r.table("users"), {index: "full_name"}) \
    .run(conn, callback)
```

## Multi indexes ##

To index a single document multiple times by different values use a multi index. For
example, you can index a blog post with an array of tags by each tag.

### Creation ###

Suppose each post has a field `tags` that maps to an array of tags. The schema of the
table `posts` would be something like:

```js
{
    title: "...",
    content: "...",
    tags: [ <tag1>, <tag2>, ... ]
}

```

```js
// Create the multi index based on the field tags
r.table("posts").indexCreate("tags", {multi: true})

// Wait for the index to be ready to use
r.table("posts").indexWait("tags").run(conn, callback)
```

### Querying ###

```js
// Get all posts with the tag "travel" (where the field tags contains "travel")
r.table("posts").getAll("travel", {index: "tags"}).run(conn, callback)

// For each tag, return the tag and the posts that have such tag
r.table("tags").eqJoin("tag", r.table("posts"), {index: "tags"}).run(conn, callback)
```

## Indexes on arbitrary ReQL expressions ##

You can create an index on an arbitrary expression by passing an anonymous
function to `indexCreate`.

```js
// A different way to do a compound index
r.table("users").indexCreate("full_name2", function(user) {
    return r.add(user("last_name"), "_", user("first_name"))
}).run(conn, callback)
```

The function you give to `indexCreate` must be deterministic. In practice this means that
that you cannot use a function that contains a sub-query or the `r.js` command.

### Using multi indexes and arbitrary expressions together ###

You can create a multi index on an arbitrary expression in similar fashion,
by passing the multi option as the last parameter to `indexCreate`.

```js
// Create a multi index on a ReQL expression
r.table("users").indexCreate("activities", r.row("hobbies").add(r.row("sports")),
    {multi: true}).run(conn, callback)
```

# Administrative operations #

## With ReQL ##

```js
// list indexes on table "users"<commit_msg>Add get/contains example<commit_after>---
layout: documentation
title: Using secondary indexes in RethinkDB
active: docs
docs_active: secondary-indexes
permalink: docs/secondary-indexes/javascript/
switcher: true
language : JavaScript 
js: [fancybox]
---

Secondary indexes are data structures that improve the speed of many
read queries at the slight cost of increased storage space and decreased
write performance.

RethinkDB supports different types of secondary indexes:

- __Simple indexes__ based on the value of a single field.
- __Compound indexes__ based on multiple fields.
- __Multi indexes__ based on arrays of values.
- Indexes based on __arbitrary expressions__.

# Using indexes #

## Simple indexes ##

Use simple indexes to efficiently retrieve and order documents by the value of a single field.

### Creation ###

```js
// Create a secondary index on the last_name attribute
r.table("users").indexCreate("last_name").run(conn, callback)
```

```js
// Wait for the index to be ready to use
r.table("users").indexWait("last_name").run(conn, callback)
```

### Querying ###

```js
// Get all users whose last name is "Smith"
r.table("users").getAll("Smith", {index: "last_name"}).run(conn, callback)

// Get all users whose last names are "Smith" or "Lewis"
r.table("users").getAll("Smith", "Lewis", {index: "last_name"}).run(conn, callback)

// Get all users whose last names are between "Smith" and "Wade"
r.table("users").between("Smith", "Wade", {index: "last_name"}).run(conn, callback)

// Efficiently order users by last name using an index
r.table("users").orderBy({index: "last_name"}).run(conn, callback)

// For each blog post, return the post and its author using the last_name index
r.table("posts").eqJoin("author_last_name", r.table("users"), {index: "last_name"}) \
    .zip().run(conn, callback)
```

{% infobox info %}
__Want to learn more about joins in RethinkDB?__ See [how to use joins](/docs/table-joins/)
to query _one to many_ and _many to many_ relations.
{% endinfobox %}

## Compound indexes ##

Use compound indexes to efficiently retrieve documents by multiple fields.

### Creation ###

```js
// Create a compound secondary index based on the first_name and last_name attributes
r.table("users").indexCreate("full_name", [r.row("first_name"), r.row("last_name")]) \
    .run(conn, callback)
```

```js
// Wait for the index to be ready to use
r.table("users").indexWait("full_name").run(conn, callback)
```

### Querying ###

```js
// Get all users whose full name is <NAME>.
r.table("users").getAll(["John", "Smith"], {index: "full_name"}).run(conn, callback)

// Get all users whose full name is between "<NAME>" and "<NAME>"
r.table("users").between(["John", "Smith"], ["Wade", "Welles"], {index: "full_name"}) \
    .run(conn, callback)

// Efficiently order users by first name and last name using an index
r.table("users").orderBy({index: "full_name"}).run(conn, callback)

// For each blog post, return the post and its author using the full_name index
r.table("posts").eqJoin("author_full_name", r.table("users"), {index: "full_name"}) \
    .run(conn, callback)
```

## Multi indexes ##

To index a single document multiple times by different values use a multi index. For
example, you can index a blog post with an array of tags by each tag.

### Creation ###

Suppose each post has a field `tags` that maps to an array of tags. The schema of the
table `posts` would be something like:

```js
{
    title: "...",
    content: "...",
    tags: [ <tag1>, <tag2>, ... ]
}

```

```js
// Create the multi index based on the field tags
r.table("posts").indexCreate("tags", {multi: true})

// Wait for the index to be ready to use
r.table("posts").indexWait("tags").run(conn, callback)
```

### Querying ###

```js
// Get all posts with the tag "travel" (where the field tags contains "travel")
r.table("posts").getAll("travel", {index: "tags"}).run(conn, callback)

// For each tag, return the tag and the posts that have such tag
r.table("tags").eqJoin("tag", r.table("posts"), {index: "tags"}).run(conn, callback)
```

## Indexes on arbitrary ReQL expressions ##

You can create an index on an arbitrary expression by passing an anonymous
function to `indexCreate`.

```js
// A different way to do a compound index
r.table("users").indexCreate("full_name2", function(user) {
    return r.add(user("last_name"), "_", user("first_name"))
}).run(conn, callback)
```

The function you give to `indexCreate` must be deterministic. In practice this means that
that you cannot use a function that contains a sub-query or the `r.js` command.

### Using multi indexes and arbitrary expressions together ###

You can create a multi index on an arbitrary expression in similar fashion,
by passing the multi option as the last parameter to `indexCreate`.

```js
// Create a multi index on a ReQL expression
r.table("users").indexCreate("activities", r.row("hobbies").add(r.row("sports")),
    {multi: true}).run(conn, callback)
```

### Use a multi index and a mapping function to speed get/contains ###

If your program frequently executes a [get](/api/javascript/get) followed by a [contains](/api/javascript/contains), that operation can be made more efficient by creating a multi index using a mapping function on the field that contains the list.

```js
// Create the index
r.table("users").indexCreate("idEquipment", function(user) {
    return user("equipment").map(function(equipment) {
        return [ user("id"), equipment ];
    });
}, {multi: true}).run(conn, callback)

// Query equivalent to get(1)('equipment').contains('tent')
r.table("users").getAll([1, "tent"], {index: "idEquipment"}).run(conn, callback)
```

# Administrative operations #

## With ReQL ##

```js
// list indexes on table "users"
{'fraction_non_alphanumeric': 0.14720577350111028, 'fraction_numerical': 0.0007401924500370096, 'mean_word_length': 4.591826176927056, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5388203', 'n_tokens_mistral': 3323, 'n_tokens_neox': 3162, 'n_words': 1239}