@loopback/docs
Version:
Documentation files rendered at [https://loopback.io](https://loopback.io)
331 lines (247 loc) • 7.79 kB
Markdown
---
title: 'Include filter'
lang: en
keywords: LoopBack 4.0, LoopBack 4, Node.js, TypeScript, OpenAPI, Filter
sidebar: lb4_sidebar
permalink: /doc/en/lb4/Include-filter.html
---
An *include* filter enables you to include results from related models in a
query over relations. (See [Relations](Relations.md) for details on how to
define relations)
The value of the include filter can be a string, an array, or an object.
{% include important.html content="You can use an _include_ filter with `find(),` `findOne()` and `findById()` methods.
" %}
### Node.js API
To query one relation:
```ts
{
include: ['relationName'];
}
```
or
```ts
{
include: [{relation: 'relationName'}];
}
```
To query multiple relations:
```ts
{
include: ['relationName1', 'relationName2'];
}
```
or
```ts
{
include: [{relation: 'relationName1'}, {relation: 'relationName2'}];
}
```
To query nested relations, use the scope field:
```ts
{
relation: 'relationName',
scope: {
include: ['nestedRelationName'],
},
}
```
Where:
- _relationName_ is the name of a relation defined in repositories. Check
[Relations](Relations.md) for details.
### REST API
To query one relation: `/modelName?filter[include][]=_relationName_` or
`/modelName?filter[include][][relation]=_relationName_`
To query multiple relations:
`/modelName?filter[include][0]=_relationName1_&filter[include][1]=_relationName2_`
or
`/modelName?filter[include][0][relation]=_relationName1_&filter[include][1][relation]=_relationName2_`
To query nested relations, as the url would get too long, we recommend to encode
it with `encodeURIComponent(JSON.stringify(filter))`:
`/modelName?filter=<encodeResult>`
You can also use
[stringified JSON format](Querying-data.md#using-stringified-json-in-rest-queries) in
a REST query.
#### Scope Filter
Please note if the scope filter contains non-string data, they won't be coerced
if you use the plain query. Only the stringified JSON format works as expected.
For example, the following REST query which includes related `users` without
their names:
`/modelName?filter[include][0][relation]=users&filter[include][0][scope][fields][name]=false`
won't hide the `name` field for `users`, because `false` is a boolean value. It
won't be coerced and will present as a string when passed to the controller
function.
A solution is to use the stringified JSON query instead to include data with
scope specified:
```ts
// Define the inclusion filter and get its encoded format
const inclusionFilter = {
include: {
relation: 'users',
scope: {
fields: {name: false},
},
},
};
const encodedFilter = encodeURIComponent(JSON.stringify(inclusionFilter));
```
and call `/modelName?filter=<encodedFilter>`
### Examples
- Return all customers with their orders:
{% include code-caption.html content="Node.js API" %}
```ts
await customerRepository.find({include: ['orders']});
```
{% include code-caption.html content="REST" %}
`/customers?filter[include][]=orders`
Or stringified JSON format:
`/customers?filter={"include":["orders"]}`
Result:
```ts
[{
id: 1,
name: 'Tom Nook',
orders:[{id: 1, desc: 'pencil'}]
},
{...}
]
```
- Return all customers with their orders and their address:
{% include code-caption.html content="Node.js API" %}
```ts
await customerRepository.find({
include: ['orders', 'address'],
});
```
{% include code-caption.html content="REST" %}
`/customers?filter[include][]=orders&filter[include][]=address`
Result:
```ts
[{
id: 1,
name: 'Tom Nook',
orders:[{id: 1, desc: 'pencil'}],
address: {'8200 Warden Ave'}
},
{...}
]
```
- Return all customers with their orders and also the shipment information of
orders:
{% include code-caption.html content="Node.js API" %}
```ts
await customerRepository.find({
include: [
{
relation: 'orders',
scope: {
include: [{relation: 'shipment'}],
},
},
],
});
```
{% include code-caption.html content="REST" %}
(using `encodeURIComponent`)
```
/customers?filter=%7B"include"%3A%5B%7B"relation"%3A"orders"%2C"scope"%3A%7B"include"%3A%5B%7B"relation"%3A"shipment"%7D%5D%7D%7D%5D%7D
```
Result:
```ts
[{
id: 1,
name: 'Tom Nook',
orders:[
{id: 123,
desc: 'pencil',
shipment: {id: 999, company: 'UPS'} // nested related models
}
],
},
{...}
]
```
#### Combined use of `fields` and `include` for a `belongsTo` relation
If you want to use both `include` and [`fields`](Fields-filter.md) to display
only specific fields of a model and a specific belongsTo relation, **you need to
add the relation foreign key in the `fields`** :
Return all posts only with field `title` and the relation `category`:
```ts
await postRepository.find({
include: [{relation: 'category'}],
fields: ['title', 'categoryId'],
});
```
#### Include with filters
In some cases, you may want to apply filters to related models to be included.
{% include note.html content="
When you apply filters to related models, the query returns results from the
first model plus any results from related models with the filter query, similar
to a \"left join\" in SQL.
" %}
LoopBack supports that with the following syntax (for example):
```ts
await postRepository.find({
include: [
{
relation: 'owner', // include the owner object
scope: {
// further filter the owner object
fields: ['username', 'email'], // only show two fields
include: {
// include orders for the owner
relation: 'orders',
scope: {
where: {orderId: 5}, // only select order with id 5
},
},
},
},
],
});
```
For real-world scenarios where only users in `$authenticated` or `$owner` roles
should have access, use `findById()`. For example, the following example uses
filters to perform pagination:
```ts
await postRepository.findById('123', {
include: [
{
relation: 'owner',
scope: {
// fetch 1st "page" with 5 entries in it
skip: 0,
limit: 5,
},
},
],
});
```
{% include important.html content="The `limit` filter will be applied on a per parent record basis. So each parent record will include a max of `limit` number of records.
Previously, we had a bug where `limit` will be applied globally, so not all parent's records will include related objects depending on the `limit` value.
To keep backward compatability with this, in the weird case it is needed, you can use `totalLimit` instead. For more details [see here](https://github.com/loopbackio/loopback-next/issues/6832)
" %}
#### Access included objects
In the Node.js API, you can simply access the returned model instance with
related items as a plain JSON object. For example:
```ts
const result = await postRepository.find({
include: [{relation: 'owner'}, {relation: 'orders'}],
});
console.log(result[0].owner, result[0].orders);
// log the related owner and order of the first returned instance
```
Note the relation properties such as `post.owner` reference a JavaScript
**function** for the relation method.
#### REST examples
These examples assume a customer model with a hasMany relationship to a reviews
model.
Return all customers including their reviews:
`/customers?filter[include][]=reviews`
Return all customers including their reviews and also their orders:
`/customers?filter[include][]=reviews&filter[include][]=orders`
Return all customers whose age is 21, including their reviews:
`/customers?filter[include][]=reviews&filter[where][age]=21`
Return first two customers including their reviews:
`/customers?filter[include][]=reviews&filter[limit]=2`
**See also**:
[Querying related models](HasMany-relation.md#querying-related-models).