diff --git a/docs/site/Include-filter.md b/docs/site/Include-filter.md index b28d03cf60bf..caa2112f70fb 100644 --- a/docs/site/Include-filter.md +++ b/docs/site/Include-filter.md @@ -2,9 +2,272 @@ title: 'Include filter' lang: en keywords: LoopBack 4.0, LoopBack 4, include -layout: readme -source: loopback-next -file: packages/metadata/README.md sidebar: lb4_sidebar permalink: /doc/en/lb4/Include-filter.html ---- \ No newline at end of file +--- + +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 + +{% include content/angular-methods-caveat.html lang=page.lang %} + +To query one relation: + +```ts +{ + include: [{relation: 'relationName'}]; +} +``` + +To query multiple relations: + +```ts +{ + include: [{relation: 'relationName1'}, {relation: 'relationName2'}]; +} +``` + +To query nested relations, use the scope field: + +```ts +{ + relation: 'relationName', + scope: { + include: [{relation: '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][][relation]=_relationName_` + +To query multiple relations: +`/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=` + +You can also use +[stringified JSON format](Querying-data.md#using-stringified-json-in-rest-queries) in +a REST query. + +### Examples + +- Return all customers with their orders: + +{% include code-caption.html content="Node.js API" %} + +```ts +await customerRepository.find({include: [{relation: 'orders'}]}); +``` + +{% include code-caption.html content="REST" %} + +`/customers?filter[include][][relation]=orders` + +Or stringified JSON format: + +`/customers?filter={"include":[{"relation":"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: [{relation: 'orders'}, {relation: 'address'}], +}); +``` + +{% include code-caption.html content="REST" %} + +`/customers?filter[include][0][relation]=orders?filter[include][1][relation]=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, + }, + }, + ], +}); +``` + +#### 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][][relation]=reviews` + +Return all customers including their reviews and also their orders: + +`/customers?filter[include][0][relation]=reviews?filter[include][1][relation]=orders` + +Return all customers whose age is 21, including their reviews: + +`/customers?filter[include][][relation]=reviews&filter[where][age]=21` + +Return first two customers including their reviews: + +`/customers?filter[include][][relation]=reviews&filter[limit]=2` + +**See also**: +[Querying related models](HasMany-relation.md#querying-related-models).