Constraint definitions

Fauna supports the following kinds of constraints:

Constraints are defined in the constraints field of the Collection document definition:

constraints: [
  {
    unique: [
      "<fieldName>", ...
    ], ...
    status: "<status>",
  },
  { check:
    { name: <constraintName>, body: <predicate> }
  }, ...
]

Unique constraint

Define unique constraints on select document fields to ensure that the values of the given fields are unique in the collection. Multiple unique constraints can be defined

Set of unique constraint definitions:

{
    unique: [
      "<fieldName>",
      . . .
    ],
    status: <constraintStatus>
}

Property Type Description

unique

List of document fields that are constrained to unique values. The fieldName value is evaluated when validating create and update requests.

You can define a constraint on a field that has the mva flag set. See Values for a description of the multivalued attribute flag (MVA) and the mva example.

status

(read-only) Constraint status:
active = Constraint is active, and a document can’t be added that conflicts with another document in the collection.
pending = Constraint isn’t yet active. If a constraint is added to a large collection, it takes time to account for existing documents, after which status transitions to active.

Unique constraints are implemented with a special index internal to Fauna. The time needed to build the index depends on the size of the collection. During that time the constraint status is pending. Also, as building an normal index consumes compute and read operations, building the index that supports the unique constraint also consume compute and read operations.

Unique constraints are applied when a new document is created or when an existing document is updated. Constraints aren’t applied retroactively to existing documents.

See collection.unique for more information.

Check constraint

A check constraint is a user-defined rule that constrain the values of a document field. Check constraints are implemented as predicates that control whether a document is written to a collection by validating that the value of a field is in an allowed set of values or range.

Check constraints are subject to the same memory and timeout limits as queries without check constraints.

Multiple check constraints can be defined

Set of check constraint definitions:

{ check:
    { name: <constraintName>,
      body: (<predicate>: () => Boolean | Null): Boolean },
    . . .
}

Property Type Description

name

(required) Check constraint name. The constraintName is used to identify the constraint in error messages and must be unique for the collection.

body

(required) Check constraint predicate. The body is an anonymous function that defines the predicate.

Check constraints can read, call UDFs, and use computed fields but can’t write. A constraint that tries to write results in an evaluation error.

When a document in a collection is created, updated, or replaced, all check constraints are evaluated by passing the document to the check constraint.

See collection.check for more information.

Examples

Unique constraint examples

These examples show you how to define different kinds of unique constraints depending on the value or values you want to constrain.

Define a simple unique constraint

  1. Given a collection definition:

    Hello.definition
    {
      name: "Hello",
      coll: Collection,
      ts: Time("2023-03-28T20:28:05.490Z"),
      indexes: {},
      constraints: [],
    }
  2. Create a unique constraint:

    Hello.definition.update({
      constraints: [
        { unique: [ "what" ] }
      ]
    })
    {
      name: "Hello",
      coll: Collection,
      ts: Time("2023-03-28T20:28:05.490Z"),
      indexes: {},
      constraints: [
        {
          unique: [
            "what",
          ],
          status: "active",
        },
      ],
    }
  3. Create a document and populate it with the constrained field. The document is created successfully:

    Hello.create({ what: "greeting" })
    {
      id: "360475803255832609",
      coll: Hello,
      ts: Time("2023-03-28T20:29:25.260Z"),
      what: "greeting",
    }
  4. Create another document and try to populate it with the same value for the constrained field. The create fails because the constrained field already has the same value:

    Hello.create({ what: "greeting" })
    Error: constraint_failure
    
    Failed unique constraint.
    
    error: Failed unique constraint.
    constraint failures:
      what: Failed unique constraint
    at *query*:1:13
      |
    1 | Hello.create({ what: "greeting" })
      |             ^^^^^^^^^^^^^^^^^^^^^^
      |

 

Define multiple constraints and constraints on a combination of values

  1. Given documents that have the shape of the following example:

    {
      id: "372518393394233409",
      coll: Customer,
      ts: Time("2023-08-08T18:41:14.200Z"),
      name: {
        first: "Kilgore",
        last: "Trout"
      },
      username: "ktrout"
    }
  2. Define two unique constraints, with one of the constraints requiring that the first and last names in combination are unique:

    Customer.definition.update( { constraints: [ { unique: [ "name.first", "name.last" ] }, { unique: "username" } ] })
    {
      name: "Customer",
      coll: Collection,
      ts: Time("2023-08-08T20:08:36.240Z"),
      constraints: [
        {
          unique: [
            "username"
          ],
          status: "active"
        },
        {
          unique: [
            "name.first",
            "name.last"
          ],
          status: "active"
        }
      ],
      history_days: 0,
      indexes: {}
    }

 

Define a unique constraint on a multivalued attribute field

Customer.byId("377240669929865281")!.update( {constraints: [ { unique: "telephone", mva: true} ]} )
{
  id: "377240669929865281",
  coll: Customer,
  ts: Time("2023-12-01T16:36:44.030Z"),
  firstName: "Alice",
  lastName: "Appleseed"
  telephone: "208-346-0715",
  constraints: [
    {
      unique: "telephone",
      mva: true
    }
  ]
}

Check constraint examples

  1. Define a hasFunds check constraint for the Customer collection that verifies that the customer balance is greater than or equal to zero:

    Collection.byName("Customer")!.update({
      constraints: [
        {
          check: {
            name: "hasFunds",
            body: "(.balance >=0)"
          }
        }
      ]
    })
    {
      name: "Customer",
      coll: Collection,
      ts: Time("2024-01-27T17:21:10.910Z"),
      constraints: [
        {
          check: {
            name: "hasFunds",
            body: "(.balance >=0)"
          }
        }
      ],
      indexes: {},
      history_days: 0
    }
  2. Given the customer named Andy with a balance of 21:

    Customer.byId("388093102421704737")
    {
      id: "388093102421704737",
      coll: Customer,
      ts: Time("2024-01-27T16:34:34.160Z"),
      name: "Andy",
      balance: 21
    }
  3. Test check constraint validation by trying to set Andy’s balance to less than zero:

    Customer.byId("388093102421704737")!.update({ balance: -50 })
    constraint_failure
    
    error: Failed to update document with id 388093102421704737 in collection `Customer`.
    constraint failures:
      Document failed check constraint `hasFunds`
    at *query*:1:44
      |
    1 | Customer.byId("388093102421704737")!.update({balance: -50})
      |                                            ^^^^^^^^^^^^^^^^
      |

    The hasFunds check constraint catches the constraint violation. Notice that the error message includes the name of the check constraint predicate.

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!