Missing field value

Problem

You want to find documents where a specific field is missing a particular field value.

Solution

You need an index that specifies the target field in the index’s terms. This index lets you search for the target field value, and by association, compute the list of documents that do not have that field value.

try
{
    Value result = await client.Query(
        CreateIndex(
            Obj(
                "name", "People_by_degrees",
                "source", Collection("People"),
                "terms", Arr(
                    Obj("field", Arr("data", "degrees"))
                )
            )
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
result, err := client.Query(
	f.CreateIndex(
		f.Obj{
			"name": "People_by_degrees",
			"source": f.Collection("People"),
			"terms": f.Arr{
				f.Obj{"field": f.Arr{"data", "degrees"}},
			},
		},
	))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
System.out.println(
    client.query(
        CreateIndex(
            Obj(
                "name", Value("People_by_degrees"),
                "source", Collection(Value("People")),
                "terms", Arr(
                    Obj("field", Arr(Value("data"), Value("degrees")))
                )
            )
        )
    ).get());
client.query(
  q.CreateIndex({
    name: 'People_by_degrees',
    source: q.Collection('People'),
    terms: [
      { field: ['data', 'degrees'] },
    ],
  })
)
.then((ret) => console.log(ret))
.catch((err) => console.error('Error: %s', err))
result = client.query(
  q.create_index({
    "name": "People_by_degrees",
    "source": q.collection("People"),
    "terms": [{"field": ["data", "degrees"]}],
  })
)
print(result)
try {
  println(Await.result(
    client.query(
      CreateIndex(
        Obj(
          "name" -> "People_by_degrees",
          "source" -> Collection("People"),
          "terms" -> Arr(
            Obj("field" -> Arr("data", "degrees"))
          )
        )
      )
    ),
    5.seconds
  ))
} catch {
  case unknown: Throwable => println("Error: " + unknown.getMessage())
}
CreateIndex({
  name: 'People_by_degrees',
  source: Collection('People'),
  terms: [
    { field: ['data', 'degrees'] },
  ]
})

This index lets us search for People documents that contain a specific degree in the degrees field. See Create documents in the Index tutorials for the definition of the People documents.

Now we can query for the difference between all documents (via the Documents function) and the documents containing a "PhD" degree, which results in the list of People documents that do not have a "PhD" degree:

try
{
    Value result = await client.Query(
        Map(
            Paginate(
                Difference(
                    Documents(Collection("People")),
                    Match(Index("People_by_degrees"), "PhD")
                )
            ),
            Lambda("ref", Get(Var("ref")))
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(ObjectV(ref: RefV(id = "304065227032363520", collection = RefV(id = "People", collection = RefV(id = "collections"))),ts: LongV(1626238047580000),data: ObjectV(first: StringV(Tim),last: StringV(Cook),age: LongV(59),degrees: Arr(StringV(BS), StringV(MBA)),letter: StringV(G)))))
result, err := client.Query(
	f.Map(
		f.Paginate(
			f.Difference(
				f.Documents(f.Collection("People")),
				f.MatchTerm(f.Index("People_by_degrees"), "PhD"),
			),
		),
		f.Lambda("ref", f.Get(f.Var("ref"))),
	))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[map[data:map[age:59 degrees:[BS MBA] first:Tim last:Cook letter:G] ref:{304065246510712320 0xc0001805a0 0xc0001805a0 <nil>} ts:1626238066150000]]]
System.out.println(
    client.query(
        Map(
            Paginate(
                Difference(
                    Documents(Collection("People")),
                    Match(Index("People_by_degrees"), Value("PhD"))
                )
            ),
            Lambda("ref", Get(Var("ref")))
        )
    ).get());
{data: [{ref: ref(id = "304065251711648256", collection = ref(id = "People", collection = ref(id = "collections"))), ts: 1626238071110000, data: {first: "Tim", last: "Cook", age: 59, degrees: ["BS", "MBA"], letter: "G"}}]}
client.query(
  q.Map(
    q.Paginate(
      q.Difference(
        q.Documents(q.Collection('People')),
        q.Match(q.Index('People_by_degrees'), 'PhD')
      )
    ),
    q.Lambda('ref', q.Get(q.Var('ref')))
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error('Error: %s', err))
{
  data: [
    {
      ref: Ref(Collection("People"), "304065275331872256"),
      ts: 1626238093630000,
      data: {
        first: 'Tim',
        last: 'Cook',
        age: 59,
        degrees: [ 'BS', 'MBA' ],
        letter: 'G'
      }
    }
  ]
}
result = client.query(
  q.map_(
    q.lambda_("ref", q.get(q.var("ref"))),
    q.paginate(
      q.difference(
        q.documents(q.collection("People")),
        q.match(q.index("People_by_degrees"), "PhD")
      )
    )
  )
)
print(result)
{'data': [{'ref': Ref(id=304065277806510592, collection=Ref(id=People, collection=Ref(id=collections))), 'ts': 1626238095990000, 'data': {'first': 'Tim', 'last': 'Cook', 'age': 59, 'degrees': ['BS', 'MBA'], 'letter': 'G'}}]}
try {
  println(Await.result(
    client.query(
      Map(
        Paginate(
          Difference(
            Documents(Collection("People")),
            Match(Index("People_by_degrees"), "PhD")
          )
        ),
        Lambda("ref", Get(Var("ref")))
      )
    ),
    5.seconds
  ))
} catch {
  case unknown: Throwable => println("Error: " + unknown.getMessage())
}
{data: [{ref: ref(id = "304065280730989056", collection = ref(id = "People", collection = ref(id = "collections"))), ts: 1626238098790000, data: {degrees: ["BS", "MBA"], last: "Cook", age: 59, letter: "G", first: "Tim"}}]}
Map(
  Paginate(
    Difference(
      Documents(Collection("People")),
      Match(Index("People_by_degrees"), "PhD")
    )
  ),
  Lambda("ref", Get(Var("ref")))
)
{
  data: [
    {
      ref: Ref(Collection("People"), "304065365448589824"),
      ts: 1626238179570000,
      data: {
        first: 'Tim',
        last: 'Cook',
        age: 59,
        degrees: [ 'BS', 'MBA' ],
        letter: 'G'
      }
    }
  ]
}

Discussion

When Fauna indexes a field containing an array value, one index entry per array item is created. That makes it straightforward to query for a single item in the array.

The Difference function is used to list the difference between all of the documents in the collection (via the Documents function) and the documents that have the "PhD" degree by using the index.

Was this article helpful?

We're sorry to hear that.
Tell us how we can improve!
Visit Fauna's Discourse forums or email docs@fauna.com

Thank you for your feedback!