Create an index

Problem

You need to create an index for a collection within the current database.

Solution

  1. Use the CreateIndex function and give the index a name, a source (the collection of documents to index); the values field is used to specify the values to include in the result for matching entries:

    Copied!
    ({
      name: "all_people",
      source: ("People"),
      values: [
        { field: ["data", "first"] },
        { field: ["data", "last"] },
        { field: ["ref"] }
      ]
    })
    {
      ref: ("all_people"),
      ts: 1631830966460000,
      active: true,
      serialized: true,
      name: 'all_people',
      source: ("People"),
      values: [
        { field: [ 'data', 'first' ] },
        { field: [ 'data', 'last' ] },
        { field: [ 'ref' ] }
      ],
      partitions: 8
    }
    Query metrics:
    •    bytesIn:   197

    •   bytesOut:   336

    • computeOps:     1

    •    readOps:     0

    •   writeOps:     8

    •  readBytes: 2,348

    • writeBytes: 1,613

    •  queryTime:  73ms

    •    retries:     0

  2. The following example adds the age field to the values definition, and sets reverse: true, to sort the results in descending order:

    Copied!
    ({
      name: "people_by_age_desc",
      source: ("People"),
      values: [
        { field: ["data", "age"], reverse: true },
        { field: ["data", "first"] },
        { field: ["data", "last"] },
        { field: ["ref"] }
      ]
    })
    {
      ref: ("people_by_age_desc"),
      ts: 1631892996810000,
      active: true,
      serialized: true,
      name: 'people_by_age_desc',
      source: ("People"),
      values: [
        { field: [ 'data', 'age' ], reverse: true },
        { field: [ 'data', 'first' ] },
        { field: [ 'data', 'last' ] },
        { field: [ 'ref' ] }
      ],
      partitions: 8
    }
    Query metrics:
    •    bytesIn:   256

    •   bytesOut:   392

    • computeOps:     1

    •    readOps:     0

    •   writeOps:     8

    •  readBytes: 2,406

    • writeBytes: 1,705

    •  queryTime:  91ms

    •    retries:     0

  3. The following example creates an index with defined terms to be able to search for document values:

    Copied!
    ({
      name: "people_by_first",
      source: ("People"),
      terms: [
        { field: ["data", "first" ] }
      ],
      values: [
        { field: ["data", "first"] },
        { field: ["data", "last"] },
        { field: ["ref"] }
      ]
    })
    {
      ref: ("people_by_first"),
      ts: 1631831198910000,
      active: true,
      serialized: true,
      name: 'people_by_first',
      source: ("People"),
      terms: [ { field: [ 'data', 'first' ] } ],
      values: [
        { field: [ 'data', 'first' ] },
        { field: [ 'data', 'last' ] },
        { field: [ 'ref' ] }
      ],
      partitions: 1
    }
    Query metrics:
    •    bytesIn:   250

    •   bytesOut:   383

    • computeOps:     1

    •    readOps:     0

    •   writeOps:     8

    •  readBytes: 2,442

    • writeBytes: 1,724

    •  queryTime: 403ms

    •    retries:     0

  4. The following examples creates an index with two terms fields:

    Copied!
    ({
      name: "people_by_first_last",
      source: ("People"),
      terms: [
        { field: ["data", "first" ] },
        { field: ["data", "last" ] }
      ],
      values: [
        { field: ["data", "first"] },
        { field: ["data", "last"] },
        { field: ["ref"] }
      ]
    })
    {
      ref: ("people_by_first_last"),
      ts: 1631893151560000,
      active: true,
      serialized: true,
      name: 'people_by_first_last',
      source: ("People"),
      terms: [ { field: [ 'data', 'first' ] }, { field: [ 'data', 'last' ] } ],
      values: [
        { field: [ 'data', 'first' ] },
        { field: [ 'data', 'last' ] },
        { field: [ 'ref' ] }
      ],
      partitions: 1
    }
    Query metrics:
    •    bytesIn:   292

    •   bytesOut:   419

    • computeOps:     1

    •    readOps:     0

    •   writeOps:     8

    •  readBytes: 2,494

    • writeBytes: 1,849

    •  queryTime: 124ms

    •    retries:     0

  5. The following example creates an index with a binding to compute a value that can be searched. The binding combines a People document’s first and last names into a fullname field:

    Copied!
    ({
      name: "people_by_fullname",
      source: {
        collection: ("People"),
        fields: {
          fullname: (
            (
              "doc",
              (
                [
                  (["data", "first"], ("doc")),
                  (["data", "last"], ("doc")),
                ],
                ' '
              )
            )
          )
        },
      },
      terms: [
        { binding: "fullname" }
      ],
      values: [
        { binding: "fullname" },
        { field: ["ref"] }
      ]
    })
    {
      ref: ("people_by_fullname"),
      ts: 1635354169660000,
      active: true,
      serialized: true,
      name: 'people_by_fullname',
      source: {
        collection: ("People"),
        fields: {
          fullname: (("doc", ([Select(["data", "first"], ("doc")), (["data", "last"], ("doc"))], " ")))
        }
      },
      terms: [ { binding: 'fullname' } ],
      values: [ { binding: 'fullname' }, { field: [ 'ref' ] } ],
      partitions: 1
    }
    Query metrics:
    •    bytesIn:   427

    •   bytesOut:   571

    • computeOps:     1

    •    readOps:     0

    •   writeOps:     8

    •  readBytes: 2,322

    • writeBytes: 1,942

    •  queryTime: 103ms

    •    retries:     0

Discussion

An index with no terms and values defined is called a "collection" index. You cannot search for any specific document with a collection index; it is used simply to make it easy to access all of the documents within a collection. With the introduction of the Documents function, you no longer need to create collection indexes.

The maximum size of an index entry, which is comprised of the terms and values content (and some overhead to distinguish multiple fields), must not exceed 64k bytes. If an index entry is too large, the query that created/updated the index entry fails.

When you define a terms field, you specify one or more fields to search for. That makes the index selective in what it returns. Note that once terms fields are defined, they are not optional for searching: every field must be specified when the index is queried.

Avoid creating a unique index that does not define terms.

If you do create a "term-less" index, the index could cause performance issues. Every time a covered document is created or updated, the index (and its history) needs to be evaluated to decide whether the document is unique or not. As the index grows larger, the evaluation for uniqueness can cause your queries involving writes to exceed the query timeout.

When you define a values field, you are specifying which field value are returned for matching index entries. If you don’t specify values, each matching index entry returns the associated document’s Reference. If you do specify values and want to include the indexed document’s Reference in results, be sure to include the ref field.

Results from an index are sorted by the defined values. If multiple fields are specified, results are ordered initially by the first field, and then the next field, and so on.

Bindings allow you to compute values to be included in the index that don’t exist within the original document. However, binding functions must be "pure" and cannot perform reads, writes, or create any other kind of side effect from their execution.

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!