Search with indexes

Searching documents in Fauna is accomplished using indexes, specifically by matching inputs against an index’s terms field.

Note that Fauna does not currently have a full-text or wildcard search capabilities. Also, indexes without defined terms cannot be used for searching.

This tutorial assumes that you have successfully prepared your database by creating the necessary collections and documents.

Exact match

Let’s say that we want to search our People collection for documents where the first name is "Alan". To do that, we need to create an index with the first field defined as one of the terms. Copy the following query, paste it into the Shell, and run it:

CreateIndex({
  name: "people_search_by_first",
  source: Collection("People"),
  terms: [
    {
      field: ["data", "first"]
    }
  ]
})

The points of interest for this query:

  • It is a good practice to name an index after its collection, its purpose, which field(s) are involved in the purpose, and the sort direction.

  • We specify a single terms field, which includes the value in each document’s first field which exists in the document’s data field.

When you run this query, the result should be similar to:

{
  "ref": Index("people_search_by_first"),
  "ts": 1565320196190000,
  "active": true,
  "serialized": true,
  "name": "people_search_by_first",
  "source": Collection("People"),
  "terms": [
    {
      "field": [
        "data",
        "first"
      ]
    }
  ],
  "partitions": 1
}

Now that the index has been created, we can use it to search our documents. Copy the following query, paste it into the Shell, and run it:

Map(
  Paginate(
    Match(Index("people_search_by_first"), "Alan")
  ),
  Lambda(
    "person",
    Get(Var("person"))
  )
)

The points of interest for this query:

  • We’re using the Match function to locate all of the entries in the people_by_first_name index that have the first name Alan.

  • We’re using the Paginate function to iterate on all of the results returned by Match.

  • We’re using the Map function to iterate on all of the results from Paginate, in order to pass them to a Lambda function. The Lambda uses the Get function to read the specified document by using the Reference returned by the index.

When you run this query, the result should be similar to:

{
  data: [
    {
      ref: Ref(Collection("People"), "240166254282805769"),
      ts: 1565299238420000,
      data: {
        first: "Alan",
        last: "Perlis",
        degrees: ["BA", "MA", "PhD"],
        letter: "A"
      }
    },
    {
      ref: Ref(Collection("People"), "240166254282801673"),
      ts: 1565299238420000,
      data: {
        first: "Alan",
        last: "Turing",
        degrees: ["BA", "MA", "MS", "PhD"],
        letter: "B"
      }
    }
  ]
}

Array field matches

When a document has a field containing an array of items, and that field is indexed, Fauna creates distinct index entries for each item in the field’s array. That makes it easy to search for any item in the array.

Our People documents contain the degrees field, which is an array with varying numbers of items. We can search on the degrees field items by creating an appropriate index. Copy the following query, paste it into the Shell, and run it:

CreateIndex({
  name: "people_search_by_degrees",
  source: Collection("People"),
  terms: [
    {
      field: ["data", "degrees"]
    }
  ]
})

The only difference between this index and the Exact match index is that we’re defining the degrees field as one of the terms.

After the index has been created, we can use it to search for our documents. Let’s find out which People documents have an MBA degree. Copy the following query, paste it into the Shell, and run it.

Map(
  Paginate(
    Match(Index("people_search_by_degrees"), "MBA")
  ),
  Lambda(
    "person",
    Get(Var("person"))
  )
)

This query differs from the Exact match query only in the index that we are using, and the search term, MBA.

When you run this query, the result should be similar to:

{
  data: [
    {
      ref: Ref(Collection("People"), "240166254282802697"),
      ts: 1565299238420000,
      data: {
        first: "Tim",
        last: "Cook",
        degrees: ["BS", "MBA"],
        letter: "G"
      }
    }
  ]
}

term1 or term2 matches

Suppose we want to search for people where the first name is Alan or the first name is Tim. To do that, we need to use one of Fauna’s Set functions, Union.

Copy the following query, paste it into the Shell, and run it:

Map(
  Paginate(
    Union(
      Match(Index("people_search_by_first"), "Alan"),
      Match(Index("people_search_by_first"), "Tim")
    )
  ),
  Lambda("person", Get(Var("person")))
)

In this query, Union combines the results of the first Match with the results of the second Match, giving us the Alan-or-Tim results that we’re looking for.

When you run this query, the result should be similar to:

{
  "data": [
    {
      "ref": Ref(Collection("People"), "240166254282801673"),
      "ts": 1565299238420000,
      "data": {
        "first": "Alan",
        "last": "Turing",
        "letter": "B"
      }
    },
    {
      "ref": Ref(Collection("People"), "240166254282802697"),
      "ts": 1565299238420000,
      "data": {
        "first": "Tim",
        "last": "Cook",
        "letter": "G"
      }
    },
    {
      "ref": Ref(Collection("People"), "240166254282805769"),
      "ts": 1565299238420000,
      "data": {
        "first": "Alan",
        "last": "Perlis",
        "letter": "A"
      }
    }
  ]
}

Conclusion

This tutorial has demonstrated how to search documents by exact, array, or union matches, using indexes. While it may be a bit more work than you might expect, especially if you are familiar with SQL searching, Fauna’s searching can provide similar results provided that you create all of the indexes required for your searching situations.

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!