Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: adding working with data pages #4970

Merged
merged 8 commits into from
Apr 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions docs/site/Fields-filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: 'Fields filter'
lang: en
keywords: LoopBack 4.0, LoopBack 4, fields
sidebar: lb4_sidebar
permalink: /doc/en/lb4/Fields-filter.html
---

A _fields_ filter specifies properties (fields) to include or exclude from the
results.

### Node.js API

agnes512 marked this conversation as resolved.
Show resolved Hide resolved
{% include content/angular-methods-caveat.html lang=page.lang %}

<pre>
{ fields: {<i>propertyName</i>: <true|false>, <i>propertyName</i>: <true|false>, ... } }
</pre>

Where:

- _propertyName_ is the name of the property (field) to include or exclude.
- `<true|false>` signifies either `true` or `false` Boolean literal. Use `true`
to include the property or `false` to exclude it from results.

By default, queries return all model properties in results. However, if you
specify at least one fields filter with a value of `true`, then by default the
query will include **only** those you specifically include with filters.

### REST API

{% include warning.html content="
As a known bug, the option `<false>` does not work for url for now. Please include the properties you need or use the [stringified JSON format](Querying-data.html#using-stringified-json-in-rest-queries) to meet your requirement. The bug is tracked in the GH issue [#4992](https://github.com/strongloop/loopback-next/issues/4992)" %}

<pre>
filter[fields][<i>propertyName</i>]=<true>&filter[fields][<i>propertyName</i>]=<true>...
</pre>

Note that to include more than one field in REST, use multiple filters.

Check out the usage of
[stringified JSON format](Querying-data.html#using-stringified-json-in-rest-queries)
in a REST query.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a URL example of stringified JSON format for fields filter here? It would be very helpful for our readers to see an example right here without having to navigate away to the link where they will actually see an example for the where filter. Let the link be there, though. Small thing, but makes a big difference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for reminding me! I just realized that the url works well with the stringified JSON ( it has a bug with pure url, see #4992). It will be a good workaround for fields!

### Examples

Return customer information only with `name` and `address`, and hide their `id`:

{% include code-caption.html content="Node.js API" %}

```ts
await customerRepository.find({fields: {id: false, name: true, address: true}});
```

{% include code-caption.html content="REST" %}

Include all required properties as a workaround:
`/customers?filter[fields][name]=true&filter[fields][address]=true`

Or use stringified JSON format:

`/orders?filter={"fields":{"name":true,"address":true,"id":false}}`

Returns:

```ts
[
{
name: 'Mario',
address: '8200 Warden Ave'
},
{
name: 'Luigi',
address: '999 Avenue Rd'
},
...
]
```

Exclude the `password` property:

{% include code-caption.html content="Node.js API" %}

```ts
await userRepository.find({fields: {password: false}});
```

{% include code-caption.html content="REST" %}

Include all properties except `password` as a workaround:

`/users?filter[fields][name]=true&filter[fields][email]=true&filter[fields][id]=true...`
hacksparrow marked this conversation as resolved.
Show resolved Hide resolved

Or use stringified JSON format:

`/users?filter={"fields":{"password":false}}`

Notice that `fields` clause is to include/exclude the result from the
**database**, e.g if you would like to check `password` for users, the above
example would fail as `password` is undefined. If you need the property and also
want to hide it from the response, set it as a
[hidden property](Model.md#hidden-properties) in the model definition.
273 changes: 273 additions & 0 deletions docs/site/Include-filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
---
title: 'Include filter'
lang: en
keywords: LoopBack 4.0, LoopBack 4, include
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

{% 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=<encodeResult>`

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
agnes512 marked this conversation as resolved.
Show resolved Hide resolved

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).
Loading