# Queries

Using queries is simple: from your entity's `Box`, call `Query()` with conditions as arguments:

```go
query := box.Query(Device_.Location.HasPrefix("US-", false))
devices, err := query.Find()
```

### Building queries

The query in the code above uses a function `HasPrefix` on a device location. Where does this come from? ObjectBox generates a `Device_` struct for you to reference available properties conveniently. This also allows code completion in your IDE and avoids typos: correctness is checked at compile time (string based queries would only be checked at run-time).

Let's say you have the following entity defined in your package:

```go
type Device struct {
	Id       uint64
	Name     string
	Location string
	Profile  uint32
}
```

Using this input, the ObjectBox code generator creates a variable `Device_` in the same package:

```go
var Device_ = struct {
	Id       *objectbox.PropertyUint64
	Name     *objectbox.PropertyString
	Location *objectbox.PropertyString
	Profile  *objectbox.PropertyUint32
}{...}
```

You can use `Device_` to construct type-specific conditions in place and combining them, forming the full query. The following example looks for devices located in the U. S. with profile number 42.

```go
box.Query(Device_.Profile.Equals(42), Device_.Location.HasPrefix("US-", false))
```

Possibly, you can be more explicit by using the `All` function:

```go
box.Query(objectbox.All(
    Device_.Profile.Equals(42),
    Device_.Location.HasPrefix("US-", false),
))
```

While if you want to query objects that satisfy one of the given conditions, use the `Any` function:

```go
box.Query(objectbox.Any(
    Device_.Name.Equals("Dev1", false),
    Device_.Name.Equals("Dev2", false),
))
```

In this example, the query selects devices named either "Dev1" or "Dev2".

You can obviously build up more complex queries by nesting `Any` and `All` conditions.

### Reusing Queries and Parameters <a href="#reusing-queries-and-parameters" id="reusing-queries-and-parameters"></a>

If you frequently run a `Query` you should cache the `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.

Assume we want to find a list of `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:

```go
var caseSensitive = false
var query = box.Query(User_.FirstName.Equals("", caseSensitive))
```

Now at some later point we want to actually run the `Query`. To set a value for the `FirstName` parameter we call `setStringParams()` on the `Query` and pass the `FirstName` property and the new parameter value:

```go
query.SetStringParams(User_.FirstName, "Joe")
joes, _ := query.Find()
```

### Alias/As <a href="#alias" id="alias"></a>

So you might already be wondering, what happens if you have more than one condition using the same property? For this purpose you can **assign each condition an alias** by calling `Alias()` right after specifying the condition:

```go
var query = box.Query(
		User_.Age.GreaterThan().Alias("min age"),
		User_.Age.LessThan().Alias("max age"))
		
// Then use the alias when setting the parameter value
query.SetInt64Params(objectbox.Alias("min age"), 50)
query.SetInt64Params(objectbox.Alias("max age"), 100)
```

There's also an alternative, syntax for a aliases that makes it easier to maintain the code because it avoids repeating string constants:

```go
var minAgeAlias = objectbox.Alias("min age")
var maxAgeAlias = objectbox.Alias("max age")
var query = box.Query(
		User_.Age.GreaterThan().As(minAgeAlias),
		User_.Age.LessThan().As(maxAgeAlias))
		
// Then use the alias when setting the parameter value
query.SetInt64Params(minAgeAlias, 50)
query.SetInt64Params(maxAgeAlias, 100)
```

### Limit, Offset, and Pagination <a href="#limit-offset" id="limit-offset"></a>

Sometimes you only need a subset of a query, for example the first 10 elements. This is especially helpful (and resourceful) when you have a high number of entities and you cannot limit the result using query conditions only. The built `Query` has  `.Offset()` and `.Limit()` methods to help you do that

```go
query := box.Query(User_.FirstName.Equals("Joe", false))
joes, err := query.Offset(10).Limit(5).Find()
```

`Offset(n uint64):` the first `n` results are skipped.\
`Limit(n uint64):` at most `n` results of this query are returned.

### Ordering results <a href="#notable-conditions" id="notable-conditions"></a>

In addition to specifying conditions you can order the returned results:

```go
query := box.Query(User_.FirstName.Equals("Joe", false), User_.Age.OrderDesc())
joes, err := query.Find()
```

You can combine multiple order parameters and options (some options are only available for certain data types, e.g. strings have case-sensitive ordering option), such as:

```go
query := box.Query(
    User_.FirstName.Equals("Joe", false), 
    User_.LastName.OrderDesc(false), // caseSensitive bool argument
    User_.Age.OrderAsc()
)
joes, err := query.Find()
```

### Notable conditions/operators

In addition to expected conditions like `Equals()`, `NotEquals()`, `GreaterThan()` and `LessThan()` there are also conditions like:

* `Between()` to filter for values that are between the given two (inclusive)
* `In()` and `NotIn()` to filter for values that match any in the given set,
* `HasPrefix()`, `HasSuffix()` and `Contains()` for extended String filtering.

### Working with query results

You have a few options how to handle the results of a query:

* `Find()` returns a slice of the matching objects,
* `FindIds()`fetches just the IDs of the matching objects as a slice, which can be more efficient in case you don't need the whole object,
* `Remove()` deletes all the matching objects from the database (in a single transaction),
* `Count()` gives you the number of the objects that match the query,
* `Limit()` and `Offset()` let you select just part of the result (e. g. for paging)
* `DescribeParams()` is a utility function which returns a human-readable representation of the query.

### Querying linked objects (relations) <a href="#ordering-results" id="ordering-results"></a>

After creating a relation between entities, you might want to add a query condition for a property that only exists in the related entity. In SQL this is solved using JOINs. ObjectBox provides query links instead. \
Let's see how this works using an example.

Assume there is a `Person` that can be associated with multiple `Address` entities:

```go
//go:generate go run github.com/objectbox/objectbox-go/cmd/objectbox-gogen

type Person struct {
	Id       uint64
	Name     string
	Address  []*Address
}

type Address struct {
	Id     uint64
	Street string
	ZIP    string
}
```

To get a `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 `Person_.Address.Link(cs ...Conditions)` method of the generated `Person_` variable to tell that the `addresses` relation should be queried and what conditions should be used to filter the addresses:

```go
// get all Person objects named "Elmo" which have an address on "Sesame Street"
var query = BoxForPerson(ob).Query(
	Person_.name.Equals("Elmo", true),
	Person_.Address.Link(Address_.Street.Equals("Sesame Street", true)),
)
var elmosOnSesameStreet = query.Find()
```

What if we want to get a list of `Address` instead of `Person`? No problem, links are smart enough to know there's also an implicit relation in the opposite direction. Note the different `box` we're using here:

```go
// get all Address objects on "Sesame Street" linked from a Person named "Elmo"
val builder = box.query().equal(Address_.Street, "Sesame Street")
var query = BoxForAddress(ob).Query(
    Address_.Street.Equals("Sesame Street", true),
	Person_.Address.Link(Person_.Name.Equals("Elmo", true)),
)
var addressesSesameStreetWithElmo = query.Find()
```

## PropertyQuery

If you only want to return the values of a particular property and not a list of full objects you can use a [PropertyQuery](https://pkg.go.dev/github.com/objectbox/objectbox-go/objectbox#PropertyQuery). After building a query, simply call `query.Property(Property)` . For example, instead of getting all Users, to just get their email addresses:

```go
query := userBox.Query()
emails, err := query.Property(User_.Email).FindStrings(nil)
```

{% hint style="warning" %}
The returned items are **not in any particular order**, even if you did specify an order when building the query.
{% endhint %}

### Handling null values

The argument to `FindStrings()` (and similar for other types) is a value to be used if the given field is `nil` in the database. **By default, i.e. when you pass \`nil\` as the argument, these values are not returned.** However, you can specify a replacement value to return if a property is null:

```go
// includes 'unknown' instead of each null email
emails, err := userBox.Query().Property(User_.Email).FindStrings("unknown")
```

### Distinct values

The property query can also only return distinct values:

```go
pq := userBox.Query().Property(User_.FirstName)

// returns ['joe'] because by default, the case of strings is ignored.
err := pq.Distinct(true) // args: Distinct(value bool)
names := pq.FindStrings(nil)

// returns ['Joe', 'joe', 'JOE']
pq.DistinctString(true, true) // args: DistinctString(value, caseSensitive bool)
names = pq.FindStrings(nil)
```

### Aggregating values

Property queries also offer aggregate functions to directly calculate the minimum, maximum, average, sum and count of all found (non-null) values:

* `Min()` / `MinDouble()`: Finds the minimum value for the given property over all objects matching the query.
* `Max()` / `MaxFloat64()`: Finds the maximum value.
* `Sum()` / `SumFloat64()`: Calculates the sum of all values. *Note: the integer version detects overflows and returns an error in that case.*
* `Average()` : Calculates the average (always a `float64`) 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://golang.objectbox.io/queries.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
