Defensive query strategies

This section describes recommended best practices for handling queries on non-existent documents or fields.

When a document does not exist

Fauna document relationships are commonly made by storing References to other documents. However, if document A stores a reference to document B, the reference to document B is not changed in document A when document B is deleted. Subsequent queries that process document A fail when they attempt to fetch document B.

You can handle references to deleted documents by calling the If and Exists functions to test for the existence of a document before attempting to fetch it.

For example, the following query fails because the related document does not exist.

Copied!
(
  {
    spellbook: ((('spellbooks'), '101')),
    owner_ref: (['data', 'owner'], ('spellbook')),
    owner: (('owner_ref')),
  },
  {
    spellbook: (['data', 'name'], ('spellbook')),
    owner: (['data', 'name'], ('owner')),
  }
)
{
  errors: [
    {
      position: [
        'let',
        2,
        'owner'
      ],
      code: 'instance not found',
      description: 'Document not found.'
    }
  ]
}
Query metrics:
  •    bytesIn: 327

  •   bytesOut: 107

  • computeOps:   1

  •    readOps:   0

  •   writeOps:   0

  •  readBytes:   0

  • writeBytes:   0

  •  queryTime: 5ms

  •    retries:   0

The following query succeeds because it checks for the existence of the related document. The non-existence of the document can be reported, for example, by substituting an object that includes the DISAPPEARED name.

Copied!
(
  {
    spellbook: ((('spellbooks'), '101')),
    owner_ref: (['data', 'owner'], ('spellbook')),
    owner: (
      (('owner_ref')),
      (('owner_ref')),
      { data: { name: 'DISAPPEARED' } },
    ),
  },
  {
    spellbook: (['data', 'name'], ('spellbook')),
    owner: (['data', 'name'], ('owner')),
  }
)
{ spellbook: "Dallben's Spellbook", owner: 'DISAPPEARED' }
Query metrics:
  •    bytesIn:  433

  •   bytesOut:   70

  • computeOps:    1

  •    readOps:    2

  •   writeOps:    0

  •  readBytes:  108

  • writeBytes:    0

  •  queryTime: 11ms

  •    retries:    0

When a field does not exist

The flexible Fauna data model allows documents with different structures to coexist in a single collection. When evaluating documents with inconsistent field structures, attempting to access a non-existent field causes your query to fail.

You can test for the existence of a field using the If and ContainsPath functions.

For example, the following query fails because not all documents contain the extra field.

Copied!
  (
    ((('Letters'))),
    (
      'ref',
      (
        { doc: (('ref')) },
        {
          letter: (['data', 'letter'], ('doc')),
          extra: (
            [
              'Extra',
              (
                (['data', 'extra'], ('doc'))
              ),
            ],
            '-'
          ),
        }
      )
    )
  )
{
  errors: [
    {
      position: [
        'map',
        'expr',
        'in',
        'object',
        'extra',
        'concat',
        1,
        'to_string',
        'from'
      ],
      code: 'value not found',
      description: 'Value not found at path [data,extra].'
    }
  ]
}
Query metrics:
  •    bytesIn:  321

  •   bytesOut:  171

  • computeOps:    1

  •    readOps:    0

  •   writeOps:    0

  •  readBytes:    0

  • writeBytes:    0

  •  queryTime: 29ms

  •    retries:    0

The following query succeeds because the existence of the extra field is checked and if the field does not exist, it can be reported, for example, by returning UNDEFINED.

Copied!
(
  ((('Letters'))),
  (
    'ref',
    (
      { doc: (('ref')) },
      {
        letter: (['data', 'letter'], ('doc')),
        extra: (
          (['data', 'extra'], ('doc')),
          (
            [
              'Extra',
              (
                (['data', 'extra'], ('doc'))
              ),
            ],
            '-'
          ),
          'UNDEFINED',
        ),
      }
    )
  )
)
{
  data: [
    { letter: 'A', extra: 'Extra-First' },
    { letter: 'B', extra: 'Extra-second' },
    { letter: 'C', extra: 'Extra-third' },
    { letter: 'D', extra: 'Extra-4th' },
    { letter: 'E', extra: 'Extra-fifth' },
    { letter: 'F', extra: 'Extra-sixth' },
    { letter: 'G', extra: 'Extra-seventh' },
    { letter: 'H', extra: 'Extra-eighth' },
    { letter: 'I', extra: 'Extra-9th' },
    { letter: 'J', extra: 'Extra-tenth' },
    { letter: 'K', extra: 'Extra-11' },
    { letter: 'L', extra: 'Extra-' },
    { letter: 'M', extra: 'UNDEFINED' },
    { letter: 'N', extra: 'Extra-14th' },
    { letter: 'O', extra: 'Extra-fifteenth' },
    { letter: 'P', extra: 'Extra-16th' },
    { letter: 'Q', extra: 'Extra-seventeenth' },
    { letter: 'R', extra: 'Extra-18th' },
    { letter: 'S', extra: 'Extra-19th' },
    { letter: 'T', extra: 'Extra-20th' },
    { letter: 'U', extra: 'Extra-21st' },
    { letter: 'V', extra: 'Extra-22nd' },
    { letter: 'W', extra: 'Extra-twenty-third' },
    { letter: 'X', extra: 'Extra-24' },
    { letter: 'Y', extra: 'Extra-24 + 1' },
    { letter: 'Z', extra: 'UNDEFINED' }
  ]
}
Query metrics:
  •    bytesIn:   408

  •   bytesOut:   981

  • computeOps:     3

  •    readOps:    34

  •   writeOps:     0

  •  readBytes: 3,119

  • writeBytes:     0

  •  queryTime:  37ms

  •    retries:     0

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!