QueryBuilder<T>
class lets you build custom queries for your entities. Create an instance via Box.query()
. QueryBuilder
offers several methods to define query conditions for properties of an entity. To specify a property ObjectBox does not use their names as text but meta-information "underscore" classes (like User_
) that are generated during build time. The meta-information classes have a static field for each property (like User_.firstName
). This allows referencing properties safely with compile-time checks to prevent runtime errors, for example, because of typos.3.0.0
introduced a new query API that accepts complex nested conditions, e.g. the equivalent of (A or B) and (C or D)
. It now works similar to the existing Dart Query API.Box.query(condition)
and supply a condition
built using entity Property
methods, like property.equal(value)
. All properties of an entity can be accessed using its underscore class. For example, for an entity User
a property
could be User_.firstName
, a condition
using it could be User_.firstName.equal("Joe")
.QueryCondition.and(condition)
or QueryCondition.or(condition)
. This implicitly adds parentheses around the combined conditions, e.g. cond1.and(cond2)
is logically equivalent to (cond1 AND cond2)
.condition
.property.oneOf(array)
replaces the in(property, array)
(inValues(property, array)
for Kotlin) condition.condition and condition
and condition or condition
.condition & condition
and condition | conditon
condition.alias(aliasName)
to set an alias for a condition
that can later be used with the Query
setParameter methods.equal()
, notEqual()
, greater()
and less()
there are also conditions like:isNull()
and notNull()
,between()
to filter for values that are between the given two,in()
and notIn()
to filter for values that match any in the given array,startsWith()
, endsWith()
and contains()
for extended String filtering.and()
and or()
to build more complex combinations of conditions.order()
method:order()
to sort in descending order, to sort case sensitive or to specially treat null values. For example to sort the above results in descending order and case sensitive instead:find()
.findFirst()
.findUnique()
instead. It will give you a single result or null, if no matching entity was found and throw an exception if there was more than one result.Query
object and re-use it. To make a Query
more reusable you can change the values, or query parameters, of each condition you added even after the Query
is built. Let's see how.User
with specific firstName
values. First, we build a regular Query
with an equal()
condition for firstName
. Because we have to pass an initial parameter value to equal()
but plan to override it before running the Query
later, we just pass an empty string:Query
with an actual value for the equals
condition onfirstName
:firstName
? For this purpose you can assign each parameter an alias while specifying the condition:offset:
The first offset
results are skipped.limit:
At most limit
results are returned.findLazy()
and findLazyCached()
which return a LazyList
of the query results.find()
you can stream it using stream()
:query.remove()
.property(Property)
to define the property followed by the appropriate find method.User
s, to just get their email addresses:min()
/ minDouble()
: Finds the minimum value for the given property over all objects matching the query.max()
/ maxDouble()
: Finds the maximum value.sum()
/ sumDouble()
: Calculates the sum of all values. Note: the non-double version detects overflows and throws an exception in that case.avg()
: Calculates the average (always a double) of all values.count()
: returns the number of results. This is faster than finding and getting the length of the result array. Can be combined with distinct()
to count only the number of distinct values.Person
that can be associated with multiple Address
entities:Person
with a certain name that also lives on a specific street, we need to query the associated Address
entities of a Person
. To do this, use the link()
method of the query builder to tell that the addresses
relation should be queried. Then add a condition for Address
:Address
instead of Person
? If you know ObjectBox relations well, you would probably add a @Backlink
relation to Address
and build your query using it with link()
as shown above:Address
entity (you still can if you need the @Backlink
elsewhere). Instead, we can use the backlink()
method to create a backlink to the addresses
relation from Person
just for that query:ToOne
or ToMany
property it will perform a database lookup to get its data. On each subsequent access it will use a cached version of that data.ToOne
or ToMany
values before the query results are returned. To do this call the QueryBuilder.eager
method when building your query and pass the RelationInfo
objects associated with the ToOne
and ToMany
properties to prefetch: