It is possible to search for documents where specific fields are missing or for fields that have been set to Null. Fauna does not store fields with Null values, however, Fauna's indexes have important properties which enable searching for missing fields:
- When a field specified in an index's
terms
orvalues
does not exist, that field evaluates tonull
- No index entry is stored for the document if either
- all of the index’s
terms
evaluate tonull
, or - all of the index’s
values
evaluate tonull
- all of the index’s
These characteristics can be leveraged in a variety of ways to search for documents with missing fields. The following example solutions are based on the Letters
documents created in the Index tutorials.
Solution - Index with multiple terms
The Match
function can be used to search for a null
term so long as there is at least one term that does not evaluate to null
.
Create an index with a term that you know is non-null, and a term that may be null:
CreateIndex({ name: 'Letters_by_letter_and_extra', source: Collection('Letters'), terms: [ { field: ['data', 'letter' }, { field: ['data', 'extra' } ], values: [ { field: ['data', 'letter' }, { field: ['data', 'extra' }, { field: ['ref'] }, ], })
This index can be used to find documents where thedata.extra
field is null
.
Paginate( Match(Index('Letters_by_letter_and_extra'), 'M', null) )
{ data: [ [ 'M', null, Ref(Collection("Letters"), "113") ] ] }
Solution - Index bindings
Index bindings execute when an index entry is created or updated, so that the computed value can be stored along with the index’s values
fields. This means that the has_extra
binding’s result accurately reflects whether the indexed document has an extra
field.
Create an index that includes a binding. The binding can reflect the state of a field even if that field was set to null
and is not stored.
CreateIndex({ name: 'Letters_with_extra', source: { collection: Collection('Letters'), fields: { has_extra: Query( Lambda( 'document', ContainsPath( ['data', 'extra'], Var('document') ) ) ), }, }, terms: [ { binding: 'has_extra' }, ], values: [ { field: ['data', 'letter'] }, { field: ['ref'] }, ], })
With that index, it is easy to find the documents where the has_extra
binding is false
:
Paginate( Match(Index('Letters_with_extra'), false) )
{ data: [ [ 'M', Ref(Collection("Letters"), "113") ], [ 'Z', Ref(Collection("Letters"), "126") ] ] }