Index tutorials

This section assumes that you have successfully completed the Dashboard quick start, and that you still have the Fauna Dashboard open in a browser tab/window.

If your Fauna Dashboard session has expired, log in again.

Indexes are the fundamental tool for querying your documents in Fauna. Fauna uses log-structured merge-tree indexes, unlike most SQL systems, which use B-tree indexes.

Since Fauna does not currently provide table scans, indexes are required for any queries where you do not already know all of the Refs involved.

Indexes are also key to searching, sorting, and combining results from multiple collections (typically called "joins").

This section provides a number of tutorials that demonstrate how to use indexes in various ways.

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.

Preparation

Each of the tutorials uses a common set of collections and documents.

Create collections

A collection is like an SQL table: it groups similar kinds of documents together. Unlike SQL, the documents in a Fauna collection are not required to include the same fields.

For our tutorials, we’re going to create a Letters collection, storing the letters of the alphabet plus some counting fields, plus a People collection, storing person documents that include first and last names, plus a letter identifier.

Let’s create the collections:

  1. In the Fauna Dashboard, make sure that you are using the my_db database.

    If you were already viewing the Dashboard click the Dashboard Home button at the top left.

    Click my_db in the list of databases.

  2. Click the NEW COLLECTION button.

  3. Specify Letters for the Collection Name field.

  4. Click the SAVE button.

  5. Click the NEW COLLECTION button.

  6. Specify People for the Collection Name field.

  7. Click the SAVE button.

The collections have been created. If you were using the Shell (either in the Fauna Dashboard, or fauna-shell in a terminal window), the following queries would create the collections:

CreateCollection({ name: "Letters" })
CreateCollection({ name: "People" })

Create indexes

An index is a lookup table, which makes finding documents faster, and more efficient compared to inspecting every document.

We need to create a few indexes to lookup documents within the collections that we just created:

  1. In the Fauna Dashboard, click Indexes in the left navigation panel.

  2. Click the NEW INDEX button.

  3. Select the Letters collection for the Source Collection field.

  4. Specify all_letters for the Index Name field.

  5. Click the SAVE button.

  6. Click the NEW INDEX button.

  7. Select the People collection for the Source Collection field.

  8. Specify all_people for the Index Name field.

  9. Click the SAVE button.

The indexes have been created. If you were using the Shell (either in the Fauna Dashboard, or fauna-shell in a terminal window), the following queries would create the indexes:

CreateIndex({ name: "all_letters", source: Collection("Letters") })
CreateIndex({ name: "all_people", source: Collection("People") })

The indexes that we have created are called "collection indexes", because that have no terms defined to help us search for specific fields, and no values defined to report specific fields in the results. These indexes just make it easy to fetch all of the documents in a collection.

You can use the Documents function instead of collection indexes.

Create documents

A document is equivalent to an SQL record; it stores values for named fields (in SQL, "columns"). The notable differences are:

  • Fauna documents do not have to have the same field structure as any other document in the same collection.

  • Fields in Fauna documents can contain documents/nested data.

Let’s create some documents for the Letters collection. Copy the following query, paste it into your Shell, and run it:

Map(
  [
    [ "101", { letter: "A", extra: "First" } ],
    [ "102", { letter: "B", extra: "second" } ],
    [ "103", { letter: "C", extra: "third" } ],
    [ "104", { letter: "D", extra: "4th" } ],
    [ "105", { letter: "E", extra: "fifth" } ],
    [ "106", { letter: "F", extra: "sixth" } ],
    [ "107", { letter: "G", extra: "seventh" } ],
    [ "108", { letter: "H", extra: "eighth" } ],
    [ "109", { letter: "I", extra: "9th" } ],
    [ "110", { letter: "J", extra: "tenth" } ],
    [ "111", { letter: "K", extra: 11 } ],
    [ "112", { letter: "L", extra: "" } ],
    [ "113", { letter: "M" } ],
    [ "114", { letter: "N", extra: "14th" } ],
    [ "115", { letter: "O", extra: "fifteenth" } ],
    [ "116", { letter: "P", extra: "16th" } ],
    [ "117", { letter: "Q", extra: "seventeenth" } ],
    [ "118", { letter: "R", extra: "18th" } ],
    [ "119", { letter: "S", extra: "19th" } ],
    [ "120", { letter: "T", extra: "20th" } ],
    [ "121", { letter: "U", extra: "21st" } ],
    [ "122", { letter: "V", extra: "22nd" } ],
    [ "123", { letter: "W", extra: "twenty-third" } ],
    [ "124", { letter: "X", extra: 24 } ],
    [ "125", { letter: "Y", extra: "24 + 1" } ],
    [ "126", { letter: "Z" } ]
  ],
  Lambda(
    ["dID", "data"],
    Create(Ref(Collection("Letters"), Var("dID")), { data: Var("data") })
  )
)

The points of interest for this query:

  • We’re using the Map function to process an array of arrays, with the inner array containing a document ID (a string-encoded 64-bit integer) and an object representing the document we wish to create in Fauna.

    We’re using the document ID to create documents with a known numeric identifier, rather than the number that Fauna would auto-generate for us. Specified document IDs can make working with particular documents notably easier.

  • We’re using a Lambda function to process each item in the document array, where each item contains a document ID and the data for the corresponding document.

  • Each invocation of the Lambda function creates a new document in the Letters collection, using the Var function to apply the value of the dID variable as the document ID, and the data variable as the document’s data.

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

[
  {
    "ref": Ref(Collection("Letters"), "101"),
    "ts": 15652991764850000,
    "data": {
      "letter": "A",
      "extra": "First"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "102"),
    "ts": 15652991764850000,
    "data": {
      "letter": "B",
      "extra": "second"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "103"),
    "ts": 15652991764850000,
    "data": {
      "letter": "C",
      "extra": "third"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "104"),
    "ts": 15652991764850000,
    "data": {
      "letter": "D",
      "extra": "4th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "105"),
    "ts": 15652991764850000,
    "data": {
      "letter": "E",
      "extra": "fifth"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "106"),
    "ts": 15652991764850000,
    "data": {
      "letter": "F",
      "extra": "sixth"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "107"),
    "ts": 15652991764850000,
    "data": {
      "letter": "G",
      "extra": "seventh"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "108"),
    "ts": 15652991764850000,
    "data": {
      "letter": "H",
      "extra": "eighth"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "109"),
    "ts": 15652991764850000,
    "data": {
      "letter": "I",
      "extra": "9th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "110"),
    "ts": 15652991764850000,
    "data": {
      "letter": "J",
      "extra": "tenth"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "111"),
    "ts": 15652991764850000,
    "data": {
      "letter": "K",
      "extra": 11
    }
  },
  {
    "ref": Ref(Collection("Letters"), "112"),
    "ts": 15652991764850000,
    "data": {
      "letter": "L",
      "extra": ""
    }
  },
  {
    "ref": Ref(Collection("Letters"), "113"),
    "ts": 15652991764850000,
    "data": {
      "letter": "M"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "114"),
    "ts": 15652991764850000,
    "data": {
      "letter": "N",
      "extra": "14th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "115"),
    "ts": 15652991764850000,
    "data": {
      "letter": "O",
      "extra": "fifteenth"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "116"),
    "ts": 15652991764850000,
    "data": {
      "letter": "P",
      "extra": "16th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "117"),
    "ts": 15652991764850000,
    "data": {
      "letter": "Q",
      "extra": "seventeenth"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "118"),
    "ts": 15652991764850000,
    "data": {
      "letter": "R",
      "extra": "18th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "119"),
    "ts": 15652991764850000,
    "data": {
      "letter": "S",
      "extra": "19th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "120"),
    "ts": 15652991764850000,
    "data": {
      "letter": "T",
      "extra": "20th"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "121"),
    "ts": 15652991764850000,
    "data": {
      "letter": "U",
      "extra": "21st"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "122"),
    "ts": 15652991764850000,
    "data": {
      "letter": "V",
      "extra": "22nd"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "123"),
    "ts": 15652991764850000,
    "data": {
      "letter": "W",
      "extra": "twenty-third"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "124"),
    "ts": 15652991764850000,
    "data": {
      "letter": "X",
      "extra": 24
    }
  },
  {
    "ref": Ref(Collection("Letters"), "125"),
    "ts": 15652991764850000,
    "data": {
      "letter": "Y",
      "extra": "24 + 1"
    }
  },
  {
    "ref": Ref(Collection("Letters"), "126"),
    "ts": 1565299176485000,
    "data": {
      "letter": "Z"
    }
  }
]

Now, let’s create some documents for the People collection. Copy the following query, paste it into your Shell, and run it:

Map(
  [
    {
      first: "Alan",    last: "Perlis",
      degrees: ['BA', 'MA', 'PhD'], letter: "A",
    },
    {
      first: "Alan",    last: "Turing",
      degrees: ['BA', 'MA', 'MS', 'PhD'], letter: "B",
    },
    {
      first: "Grace",   last: "Hopper",
      degrees: ['BA', 'MA', 'PhD'], letter: "C",
    },
    {
      first: "Leslie",  last: "Lamport",
      degrees: ['BS', 'MA', 'PhD'],
    },
    {
      first: "Marvin",  last: "Minsky",
      degrees: ['BA', 'PhD'], letter: 1,
    },
    {
      first: "Stephen", last: "Cook",
      degrees: ['BS', 'PhD'], letter: "F",
    },
    {
      first: "Tim",     last: "Cook",
      degrees: ['BS', 'MBA'], letter: "G",
    }
  ],
  Lambda(
    "person",
    Create(Collection("People"), { data: Var("person") })
  )
)

This query is very similar to the query we used to create documents in the Letters collection. The People documents that we have created just differ in structure.

You may have noticed that both queries vary the definition of the last field. These variations are used in the tutorials to highlight behavioral differences.

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

[
  {
    "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"
    }
  },
  {
    "ref": Ref(Collection("People"), "240166254282806793"),
    "ts": 1565299238420000,
    "data": {
      "first": "Grace",
      "last": "Hopper",
      "degrees": [ 'BA', 'MA', 'PhD' ],
      "letter": "C"
    }
  },
  {
    "ref": Ref(Collection("People"), "240166254282803721"),
    "ts": 1565299238420000,
    "data": {
      "first": "Leslie",
      "last": "Lamport",
      "degrees": [ 'BS', 'MA', 'PhD' ]
    }
  },
  {
    "ref": Ref(Collection("People"), "240166254282804745"),
    "ts": 1565299238420000,
    "data": {
      "first": "Marvin",
      "last": "Minsky",
      "degrees": [ 'BA', 'PhD' ],
      "letter": 1
    }
  },
  {
    "ref": Ref(Collection("People"), "240166254282807817"),
    "ts": 1565299238420000,
    "data": {
      "first": "Stephen",
      "last": "Cook",
      "degrees": [ 'BS', 'PhD' ],
      "letter": "F"
    }
  },
  {
    "ref": Ref(Collection("People"), "240166254282802697"),
    "ts": 1565299238420000,
    "data": {
      "first": "Tim",
      "last": "Cook",
      "degrees": [ 'BS', 'MBA' ],
      "letter": "G"
    }
  }
]

Now that we have our collections and documents created, we’re all set to start working through the index tutorials.

Next steps

The tutorials are listed in order of increasing complexity, but they can be followed in any order.