Documents

Every record, of any kind, in a Fauna database is stored as an object called a document. Documents are made up of fields and their associated value, just like a JSON object. The value for any key can itself be a document.

See the limits page for details on document size and transaction limits.

Every document belongs to a specific collection, similar to a table in other database systems, which groups similar documents together. Documents within collections are not required to share the same structure. Collections belong to a specific database.

Even the definitions of Databases, Collections, Keys, Indexes, and user-defined functions, are all documents. They exist within internal Fauna collections of the same name.

All documents have a set of common characteristics:

  • Documents have an identifier called a Reference (or just Ref). A document’s Reference is a compound value comprising its collection along with a unique document ID. A Reference is a unique identifier for the document within the scope of the database in which it is stored. The document ID is a string-encoded 64-bit integer.

    The following query retrieves a specific document by its Reference, and returns a result that includes the document, the reference, and the components of the reference: the collection reference and the document ID:

    try
    {
        Value result = await client.Query(
            Let(
                "doc", Get(Ref(Collection("users"), "1"))
            ).In(
                Obj(
                    "document", Var("doc"),
                    "reference", Select("ref", Var("doc")),
                    "reference collection", Select(
                        Arr("ref", "collection"),
                        Var("doc")
                    ),
                    "document ID", Select(
                        Arr("ref", "id"),
                        Var("doc")
                    )
                )
            )
        );
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine($"ERROR: {e.Message}");
    }
    ObjectV(document: ObjectV(ref: RefV(id = "1", collection = RefV(id = "users", collection = RefV(id = "collections"))),ts: LongV(1625505840300000),data: ObjectV(name: StringV(Alice Crypto),email: StringV(alice@site.example.com))),reference: RefV(id = "1", collection = RefV(id = "users", collection = RefV(id = "collections"))),reference collection: RefV(id = "users", collection = RefV(id = "collections")),document ID: StringV(1))
    result, err := client.Query(
    	f.Let().Bind(
    		"doc", f.Get(f.Ref(f.Collection("users"), "1")),
    	).In(
    		f.Obj{
    			"document": f.Var("doc"),
    			"reference": f.Select("ref", f.Var("doc")),
    			"reference collection": f.Select(
    				f.Arr{"ref", "collection"},
    				f.Var("doc"),
    			),
    			"document ID": f.Select(
    				f.Arr{"ref", "id"},
    				f.Var("doc"),
    			),
    		},
    	))
    
    if err != nil {
    	fmt.Fprintln(os.Stderr, err)
    } else {
    	fmt.Println(result)
    }
    map[document:map[data:map[email:alice@site.example.com name:Alice Crypto] ref:{1 0xc0000925a0 0xc0000925a0 <nil>} ts:1625506145900000] document ID:1 reference:{1 0xc000092780 0xc000092780 <nil>} reference collection:{users 0xc000092870 0xc000092870 <nil>}]
    client.query(
      q.Let(
        {
          doc: q.Get(q.Ref(q.Collection('users'), '1')),
        },
        {
          document: q.Var('doc'),
          reference: q.Select('ref', q.Var('doc')),
          'reference collection': q.Select(['ref', 'collection'], q.Var('doc')),
          'document ID': q.Select(['ref', 'id'], q.Var('doc')),
        }
      )
    )
    .then((res) => console.log(res))
    .catch((err) => console.error(
      'Error: [%s] %s: %s',
      err.name,
      err.message,
      err.errors()[0].description,
    ))
    {
      document: {
        ref: Ref(Collection("users"), "1"),
        ts: 1625505428470000,
        data: { name: 'Alice Crypto', email: 'alice@site.example.com' }
      },
      reference: Ref(Collection("users"), "1"),
      'reference collection': Collection("users"),
      'document ID': '1'
    }
    result = client.query(
      q.let(
        {
          "doc": q.get(q.ref(q.collection("users"), "1")),
        },
        {
          "document": q.var("doc"),
          "reference": q.select("ref", q.var("doc")),
          "reference collection": q.select(["ref", "collection"], q.var("doc")),
          "document ID": q.select(["ref", "id"], q.var("doc")),
        }
      )
    )
    print(result)
    {'document': {'ref': Ref(id=1, collection=Ref(id=users, collection=Ref(id=collections))), 'ts': 1625505236270000, 'data': {'name': 'Alice Crypto', 'email': 'alice@site.example.com'}}, 'reference': Ref(id=1, collection=Ref(id=users, collection=Ref(id=collections))), 'reference collection': Ref(id=users, collection=Ref(id=collections)), 'document ID': '1'}
    Let(
      {
        doc: Get(Ref(Collection("users"), "1")),
      },
      {
        "document": Var("doc"),
        "reference": Select("ref", Var("doc")),
        "reference collection": Select(["ref", "collection"], Var("doc")),
        "document ID": Select(["ref", "id"], Var("doc")),
      }
    )
    {
      document: {
        ref: Ref(Collection("users"), "1"),
        ts: 1625504819720000,
        data: { name: 'Alice Crypto', email: 'alice@site.example.com' }
      },
      reference: Ref(Collection("users"), "1"),
      'reference collection': Collection("users"),
      'document ID': '1'
    }
    Query metrics:
    •    bytesIn: 293

    •   bytesOut: 439

    • computeOps:   1

    •    readOps:   1

    •   writeOps:   0

    •  readBytes:  96

    • writeBytes:   0

    •  queryTime: 6ms

    •    retries:   0

  • User-specified documents have a timestamp that identifies when the document was most recently updated. Fauna documents are versioned — each time a document is updated, a new version is stored — and the versions are distinguished using the timestamp. When a query does not specify a timestamp, the latest versions of any documents involved are used. The timestamp — returned in the ts field — is of type Long.

    ts should not be directly manipulated. Instead, you can use the Insert and Remove functions to manipulate the history of a document at specific timestamps.

    To track timestamps independent of Fauna operations, include fields in your documents to record timestamps entirely under your control.

  • Documents can have an optional ttl field (meaning time-to-live), which is a Timestamp that indicates when the document should be removed. When a document is removed, the document’s existence ceases (as if it never existed); temporal queries cannot recover the document.

    See Temporality for more information about temporality.

  • Documents are manipulated with the same query language functions, such as get, create, update, replace, or delete. Documents returned by queries are represented as JSON objects. Within a query, a document’s fields may be accessed using the Select function.

To separate the ref and timestamp from user-defined fields, Fauna wraps each user-specified document in a metadata document for storage, and user-specified data appears in the data field. For example, when a blog post document is created, it is stored as:

{
  ref: Ref(Collection("posts"), "227576404750893579"),
  ts: 1553292644000000,
  data: {
    title: 'My blog post',
    tags: [ 'post', 'popular', 'blog' ],
    body: "Lorem ipsum..."
  }
}

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!