Filter by Field Presence
-
Documents in the same collection can have different fields.
For example, a field added to newer documents might be missing from older documents.
You can optionally use schema validation to require specific fields when documents are written. -
To filter documents by field presence:
- To find documents that contain a specified field, use
WhereExists. - To find documents that are missing a specified field, use
.Not.WhereExists. - Both are available through the DocumentQuery API.
- To find documents that contain a specified field, use
-
An explicit
nullcounts as present only when it is the value of the field you check.
If a parent on a nested path is missing ornull, or the field is an empty array, the field counts as missing.
Learn more in How field presence is determined. -
You can check field presence when querying a static index or when making a dynamic query.
When querying a static index, the check applies to the fields produced by the index's map function. -
In this article:
Find documents that CONTAIN a field
Dynamic query
-
Use
WhereExiststo return documents that contain the specified field.
Documents that are missing the field are excluded from the results. -
RavenDB uses an auto-index to process the filter, creating one if needed.
Learn more about this query type in Query a collection - with filtering. -
You can check field presence using either a field name or a nested field path, as shown below.
Filter documents by field name
The following query returns employees whose documents contain the FirstName field:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employees = session.Advanced
.DocumentQuery<Employee>()
.WhereExists("FirstName")
// Or use a lambda expression: .WhereExists(e => e.FirstName)
.ToList();
List<Employee> employees = await asyncSession.Advanced
.AsyncDocumentQuery<Employee>()
.WhereExists("FirstName")
// Or use a lambda expression: .WhereExists(e => e.FirstName)
.ToListAsync();
from Employees
where exists("FirstName")
Filter documents by nested field path
You can also check for a nested field by specifying its full path.
The following query returns employees whose documents contain Latitude at Address.Location.Latitude:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employees = session.Advanced
.DocumentQuery<Employee>()
.WhereExists("Address.Location.Latitude")
// Or use a lambda expression:
// .WhereExists(e => e.Address.Location.Latitude)
.ToList();
List<Employee> employees = await asyncSession.Advanced
.AsyncDocumentQuery<Employee>()
.WhereExists("Address.Location.Latitude")
// Or use a lambda expression:
// .WhereExists(e => e.Address.Location.Latitude)
.ToListAsync();
from Employees
where exists(Address.Location.Latitude)
Static index query
-
When querying a static index, use the index-field name in
WhereExists.
The index must include the field whose presence you want to check. -
The following index maps:
-
FirstNameto an index-field with the same name. -
Address.Location.Latitudeto an index-field namedLatitude. -
The document ID to an index-field named
Id, to retain entries for documents with missing fields.
See Static index query for missing fields for details.public class Employees_ByFieldPresence: AbstractIndexCreationTask<Employee, Employees_ByFieldPresence.IndexEntry>{public class IndexEntry{// The index-fieldspublic string Id { get; set; }public string FirstName { get; set; }public double Latitude { get; set; }}public Employees_ByFieldPresence(){Map = employees => from employee in employeesselect new IndexEntry{// Include Id so documents with missing fields still have an index entry.Id = employee.Id,FirstName = employee.FirstName,Latitude = employee.Address.Location.Latitude};}}
-
Filter documents by field name
The following example queries the Employees_ByFieldPresence index and returns employee documents that contain the FirstName field:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employees = session.Advanced
.DocumentQuery<Employee, Employees_ByFieldPresence>()
.WhereExists("FirstName")
// Or use a lambda expression: .WhereExists(e => e.FirstName)
.ToList();
List<Employee> employees = await asyncSession.Advanced
.AsyncDocumentQuery<Employee, Employees_ByFieldPresence>()
.WhereExists("FirstName")
// Or use a lambda expression: .WhereExists(e => e.FirstName)
.ToListAsync();
from index "Employees/ByFieldPresence"
where exists("FirstName")
Filter documents by a mapped nested field
The index maps the nested document field Address.Location.Latitude to an index-field named Latitude.
Use Latitude in the query:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employees = session.Advanced
.DocumentQuery<Employee, Employees_ByFieldPresence>()
.WhereExists("Latitude")
.ToList();
List<Employee> employees = await asyncSession.Advanced
.AsyncDocumentQuery<Employee, Employees_ByFieldPresence>()
.WhereExists("Latitude")
.ToListAsync();
from index "Employees/ByFieldPresence"
where exists("Latitude")
Find documents that are MISSING a field
Dynamic query
- Use
.Not.WhereExiststo return documents that are missing the specified field. - You can check for a missing field using either a field name or a nested field path, as shown below.
Filter documents by field name
The following query returns employees whose documents do not contain the field FirstName:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employeesWithoutFirstName = session.Advanced
.DocumentQuery<Employee>()
.Not.WhereExists("FirstName")
// Or use a lambda expression: .Not.WhereExists(e => e.FirstName)
.ToList();
List<Employee> employeesWithoutFirstName = await asyncSession.Advanced
.AsyncDocumentQuery<Employee>()
.Not.WhereExists("FirstName")
// Or use a lambda expression: .Not.WhereExists(e => e.FirstName)
.ToListAsync();
from Employees
where true and not exists("FirstName")
In RQL, not cannot appear immediately after where.
Use where true and not exists(...) when the missing-field condition is the first condition.
DocumentQuery adds true and automatically in this case.
Filter documents by nested field path
Use the full path to check for a missing nested field.
The following query returns employees whose documents do not contain Latitude at Address.Location.Latitude:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employeesWithoutLatitude = session.Advanced
.DocumentQuery<Employee>()
.Not.WhereExists("Address.Location.Latitude")
// Or use a lambda expression:
// .Not.WhereExists(e => e.Address.Location.Latitude)
.ToList();
List<Employee> employeesWithoutLatitude = await asyncSession.Advanced
.AsyncDocumentQuery<Employee>()
.Not.WhereExists("Address.Location.Latitude")
// Or use a lambda expression:
// .Not.WhereExists(e => e.Address.Location.Latitude)
.ToListAsync();
from Employees
where true and not exists(Address.Location.Latitude)
Static index query
-
Use
.Not.WhereExistswith the index-field name.
The field you want to check must be included in the index's map function. -
The index must also retain an entry for documents that are missing that field. The index used in this article maps the document ID to
Id, ensuring that an entry is retained even when bothFirstNameandLatitudeare missing. -
Alternatively, set Indexing.IndexEmptyEntries to
trueto retain entries for documents that are missing all mapped fields, without needing to mapIdfor this purpose.
If Indexing.IndexMissingFieldsAsNull is true,
missing mapped fields are indexed as null and count as present.
Consequently, .Not.WhereExists does not return documents whose missing fields were indexed this way.
This setting does not affect auto-indexes.
Filter documents by field name
Query the Employees_ByFieldPresence index defined above:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employeesWithoutFirstName = session.Advanced
.DocumentQuery<Employee, Employees_ByFieldPresence>()
.Not.WhereExists("FirstName")
// Or use a lambda expression: .Not.WhereExists(e => e.FirstName)
.ToList();
List<Employee> employeesWithoutFirstName = await asyncSession.Advanced
.AsyncDocumentQuery<Employee, Employees_ByFieldPresence>()
.Not.WhereExists("FirstName")
// Or use a lambda expression: .Not.WhereExists(e => e.FirstName)
.ToListAsync();
from index "Employees/ByFieldPresence"
where true and not exists("FirstName")
Filter documents by a mapped nested field
The index maps the document field Address.Location.Latitude to an index-field named Latitude.
The following query checks the Latitude index-field and returns employee documents that do not contain Latitude at Address.Location.Latitude:
- DocumentQuery
- DocumentQuery_async
- RQL
List<Employee> employeesWithoutLatitude = session.Advanced
.DocumentQuery<Employee, Employees_ByFieldPresence>()
.Not.WhereExists("Latitude")
.ToList();
List<Employee> employeesWithoutLatitude = await asyncSession.Advanced
.AsyncDocumentQuery<Employee, Employees_ByFieldPresence>()
.Not.WhereExists("Latitude")
.ToListAsync();
from index "Employees/ByFieldPresence"
where true and not exists("Latitude")
How field presence is determined
-
WhereExistschecks field presence in the index used by the query:- An explicit
nullcounts as present only when it is the value of the field you check. - If a parent on a nested path is missing or
null, the field counts as missing. - An empty array counts as missing.
- An explicit
-
These rules apply to both query types, with a configuration exception for static indexes:
-
For dynamic queries, they apply to the document field name or nested path specified in the query.
-
For static index queries, presence is checked on the fields produced by the index's map function.
For example, with the direct index-field mappingLatitude = employee.Address.Location.Latitude,
the query checksLatitude, notAddress.Location.Latitude.If
Addressis missing ornull, this mapping produces an implicitnullforLatitude,
which is not indexed by default. TheLatitudeindex-field therefore counts as missing.The Indexing.IndexMissingFieldsAsNull configuration key is
falseby default.
If set totrue, missing mapped fields are indexed asnulland count as present.
Empty arrays still count as missing, regardless of this setting.For
.Not.WhereExiststo return documents with missing fields, the index must retain entries for them.
See Static index query for missing fields for details.
-
The following examples use document field names and paths and assume the default indexing settings.
For static indexes, they assume direct mappings and retained entries for documents with missing fields,
as explained above.
| Document content | Checked path | WhereExists result | .Not.WhereExists result |
|---|---|---|---|
"FirstName": null | FirstName | Document returned ✅ | Document excluded ❌ |
No FirstName field | FirstName | Document excluded ❌ | Document returned ✅ |
"Territories": [] | Territories | Document excluded ❌ | Document returned ✅ |
"Address": { "Location": { "Latitude": null } } | Address.Location.Latitude | Document returned ✅ | Document excluded ❌ |
"Address": null | Address.Location.Latitude | Document excluded ❌ | Document returned ✅ |
"Address": { "City": "Seattle" } | Address.Location.Latitude | Document excluded ❌ | Document returned ✅ |
Syntax
WhereExists
- DocumentQuery
- DocumentQuery_async
IDocumentQuery<T> WhereExists(string fieldName);
IDocumentQuery<T> WhereExists<TValue>(Expression<Func<T, TValue>> propertySelector);
IAsyncDocumentQuery<T> WhereExists(string fieldName);
IAsyncDocumentQuery<T> WhereExists<TValue>(Expression<Func<T, TValue>> propertySelector);
| Parameter | Type | Description |
|---|---|---|
| fieldName | string | For a dynamic query, the document field name or nested path. For a static index query, the index field name. |
| propertySelector | Expression<Func<T, TValue>> | A lambda expression that selects the field. For static index queries, the resulting field name must match a field in the index. |
Not
The Not property negates the next filtering condition.
Place it immediately before WhereExists to search for missing fields:
.Not.WhereExists("FirstName")
RQL
// Find documents with the field.
where exists(FieldName)
// Find documents without the field.
where true and not exists(FieldName)