From 2378a55dacd8e5ed6dc7b6cbd831935363fe0f27 Mon Sep 17 00:00:00 2001 From: Agnes Lin Date: Fri, 27 Mar 2020 14:16:05 -0400 Subject: [PATCH] docs: querying data --- docs/site/Querying-data.md | 211 +++++++++++++++++++++++-------------- 1 file changed, 129 insertions(+), 82 deletions(-) diff --git a/docs/site/Querying-data.md b/docs/site/Querying-data.md index 8683ce1fe4a7..5e47bbc22903 100644 --- a/docs/site/Querying-data.md +++ b/docs/site/Querying-data.md @@ -2,19 +2,19 @@ lang: en title: 'Querying data' keywords: LoopBack 4.0, LoopBack 4 -layout: readme -source: loopback-next -file: packages/metadata/README.md sidebar: lb4_sidebar permalink: /doc/en/lb4/Querying-data.html -summary: -- --- ## Overview A _query_ is a read operation on models that returns a set of data or results. -As we introduced in [Working with data](Working-with-data.md), repositories add behavior to models. Once you have them set up, you can query instances using a Node.js API and a REST API with _filters_ as outlined in the following table. Filters specify criteria for the returned data set. -The capabilities and options of the two APIs are the same. The only difference is the syntax used in HTTP requests versus Node function calls. In both cases, LoopBack models return JSON. +As we introduced in [Working with data](Working-with-data.md), repositories add +behavior to models. Once you have them set up, you can query instances using a +Node.js API and a REST API with _filters_ as outlined in the following table. +Filters specify criteria for the returned data set. The capabilities and options +of the two APIs are the same. The only difference is the syntax used in HTTP +requests versus Node function calls. In both cases, LoopBack models return JSON. @@ -30,59 +30,58 @@ The capabilities and options of the two APIs are the same. The only difference i Find all model instances using specified filters.
- find(filter, callback) + find(filter, options?) Where filter is a JSON object containing the query filters. - See Filters below. GET /modelName?filter... - See Model REST API - Find matching instances. - See Filters below.
Find first model instance using specified filters. - findOne(filter, callback) + findOne(filter, options?) Where filter is a JSON object containing the query filters. - See Filters below. GET /modelName/findOne?filter... - See Model REST API - Find first instance. - See Filters below.
Find instance by ID. - findById(id, [filter,] callback) + findById(id, filter?, options?) Where optional filter is a JSON object containing the query filters. - See Filters below. - GET /modelName/modelID - See Model REST API - Find instance by ID.
-LB4 supports standard REST syntax and also "stringified JSON" in REST queries. Please read on to see more details and examples of different types of `filter` and example usages of REST API. +LB4 supports standard REST syntax and also "stringified JSON" in REST queries. +Please read on to see more details and examples of different types of `filter` +and example usages of REST API. ## Filters -LoopBack supports the following filters: +LoopBack supports a specific filter syntax: it's a lot like SQL, but designed +specifically to serialize safely without injection and to be native to +JavaScript. + +LoopBack 4 supports the following kinds of filters: -* [Fields filter](Fields-filter.html) -* [Include filter](Include-filter.html) -* [Limit filter](Limit-filter.html) -* [Order filter](Order-filter.html) -* [Skip filter](Skip-filter.html) -* [Where filter](Where-filter.html) +- [Fields filter](Fields-filter.md) +- [Include filter](Include-filter.md) +- [Limit filter](Limit-filter.md) +- [Order filter](Order-filter.md) +- [Skip filter](Skip-filter.md) +- [Where filter](Where-filter.md) -More additional examples of each kind of filter can be found in the individual articles on filters (for example [Where filter](Where-filter.md)). Those examples show different syntaxes in REST and Node.js. +More additional examples of each kind of filter can be found in the individual +articles on filters (for example [Where filter](Where-filter.md)). Those +examples show different syntaxes in REST and Node.js. The following table describes LoopBack's filter types: @@ -96,7 +95,7 @@ The following table describes LoopBack's filter types: - fields + fields Object, Array, or String Specify fields to include in or exclude from the response. @@ -104,7 +103,7 @@ The following table describes LoopBack's filter types: - include + include String, Object, or Array Include results from related models, for relations such as belongsTo and hasMany. @@ -112,7 +111,7 @@ The following table describes LoopBack's filter types: - limit + limit Number Limit the number of instances to return. @@ -120,7 +119,7 @@ The following table describes LoopBack's filter types: - order + order String Specify sort order: ascending or descending. @@ -128,7 +127,7 @@ The following table describes LoopBack's filter types: - skip (offset) + skip (offset) Number Skip the specified number of instances. @@ -136,7 +135,7 @@ The following table describes LoopBack's filter types: - where + where Object Specify search criteria; similar to a WHERE clause in SQL. @@ -146,7 +145,8 @@ The following table describes LoopBack's filter types: -The following is an example of using the `find()` method with both a _where_ and a _limit_ filter: +The following is an example of using the `find()` method with both a _where_ and +a _limit_ filter: ```ts await accountRepository.find({where: {name: 'John'}, limit: 3}); @@ -158,11 +158,33 @@ Equivalent using REST: ## Syntax -In both Node.js API and REST, you can use any number of filters to define a query. +In both Node.js API and REST, you can use any number of filters to define a +query. + +### Node.js syntax + +Specify filters as the first argument to `find*()`: + +```ts +{ filterType: spec, filterType: spec, ... } +``` + +There is no theoretical limit on the number of filters you can apply. + +Where: + +- *filterType* is the filter: [where](Where-filter.md), + [include](Include-filter.md), [order](Order-filter.md), + [limit](Limit-filter.md), [skip](Skip-filter.md), or + [fields](Fields-filter.md). +- *spec* is the specification of the filter: for example for a *where* filter, + this is a logical condition that the results must match. For + an *include* filter it specifies the related fields to include. ### REST syntax -Specify filters in the [HTTP query string](http://en.wikipedia.org/wiki/Query_string): +Specify filters in +the [HTTP query string](http://en.wikipedia.org/wiki/Query_string): `/modelName?filter=[filterType1]=val1&filter[filterType2]=val2...` @@ -170,53 +192,67 @@ or `/modelName/id?filter=[filterType1]=val1&filter[filterType2]=val2...` -The number of filters that you can apply to a single request is limited only by the maximum URL length, which generally depends on the client used. +The number of filters that you can apply to a single request is limited only by +the maximum URL length, which generally depends on the client used. {% include important.html content=" There is no equal sign after `?filter` in the query string; for example `http://localhost:3000/api/books?filter[where][id]=1`  " %} -{% include note.html content="See [https://github.com/hapijs/qs](https://github.com/hapijs/qs) for more details. -" %} - -### Node syntax +If the filter gets too long, you can encode it. For example: -Specify filters as the first argument to `find()` and `findOne()`:  +```ts +const filter = { + include: [ + { + relation: 'orders', + scope: { + include: [{relation: 'manufacturers'}], + }, + }, + ], +}; -```javascript -{ filterType: spec, filterType: spec, ... } +encodeURIComponent(JSON.stringify(filter)); ``` -There is no theoretical limit on the number of filters you can apply. +the url would be: -Where: +`/customers?filter=` -* _filterType_ is the filter: [where](Where-filter.html), [include](Include-filter.html), [order](Order-filter.html), - [limit](Limit-filter.html), [skip](Skip-filter.html), or [fields](Fields-filter.html). -* _spec_ is the specification of the filter: for example for a _where_ filter, this is a logical condition that the results must match. - For an _include_ filter it specifies the related fields to include. +{% include important.html content=" A REST query must include the literal string +\"filter\" in the URL query string. The Node.js API call does not include the +literal string \"filter\" in the JSON."} + +{% include tip.html content=" +If you are trying [query filters](#filters) with curl, use the `-g` or `--globoff`  option to use brackets `[` and `]` in request URLs. +" %} ### Using "stringified" JSON in REST queries -Instead of the standard REST syntax described above, you can also use "stringified JSON" in REST queries. -To do this, simply use the JSON specified for the Node syntax, as follows: +Instead of the standard REST syntax described above, you can also use +"stringified JSON" in REST queries. To do this, simply use the JSON specified +for the Node.js syntax, as follows: -`?filter={ Stringified-JSON }` +`?filter={ Stringified-JSON }` -where _Stringified-JSON_ is the stringified JSON from Node syntax. However, in the JSON all text keys/strings must be enclosed in quotes ("). +where *Stringified-JSON* is the stringified JSON from Node.js syntax. However, +in the JSON all text keys/strings must be enclosed in quotes ("). -{% include important.html content=" -When using stringified JSON, you must use an equal sign after `?filter` in the query string. +{% include important.html content=" When using stringified JSON, you must use an +equal sign after `?filter` in the query string. -For example: `http://localhost:3000/api/books?filter={%22where%22:{%22id%22:2}}`  -" %} +For example: `http://localhost:3000/books?filter={%22where%22:{%22id%22:2}}`  " +%} For example: `GET /api/activities/findOne?filter={"where":{"id":1234}}` ### Build filters with FilterBuilder -Besides writing the filter yourself, you can also use [`FilterBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.filterbuilder.html) to help you create or combine `where` clauses. +Besides writing the filter yourself, you can also use +[`FilterBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.filterbuilder.html) +to help you create or combine `where` clauses. For example, you can build the filter @@ -226,6 +262,7 @@ const filter = { include: [{relation: 'orders', scope: {where: {name: 'toy'}}] }; ``` + with the `FilterBuilder`: ```ts @@ -240,12 +277,12 @@ const filterBuilder = new FilterBuilder(); .build(); ``` -Another usage of [`FilterBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.filterbuilder.html) is to combine the `where` clause by using `FilterBuilder.impose`. For example, +Another usage of +[`FilterBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.filterbuilder.html) +is to combine the `where` clause by using `FilterBuilder.impose`. For example, ```ts -const filter = new FilterBuilder() - .limit(5) - .where({id: 101}); +const filter = new FilterBuilder().limit(5).where({id: 101}); filter.impose({where: {id: 999, name: 'LoopBack'}}); ``` @@ -260,9 +297,11 @@ The `where` clauses is combined as: } ``` -This also can be done with the [`WhereBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.wherebuilder.html). See more examples in the [`Where Filter`](Where-filter.md#wherebuilder) page. +This also can be done with the +[`WhereBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.wherebuilder.html). +See more examples in the [`Where Filter`](Where-filter.md#wherebuilder) page. - + 1. Prohibits hidden/protected properties from being searched -[Hidden or protected properties](https://loopback.io/doc/en/lb3/Model-definition-JSON-file.html#hidden-properties) -can expose sensitive information if they are allowed to be searched. -LoopBack introduces `prohibitHiddenPropertiesInQuery` setting at datasource/model level to control -if hidden/protected properties can be used in the `where` object. By default, its value is `true`. -For example, -{% include code-caption.html content="datasources/db.datasources.config.json" %} + [Hidden or protected properties](https://loopback.io/doc/en/lb3/Model-definition-JSON-file.html#hidden-properties) + can expose sensitive information if they are allowed to be searched. LoopBack + introduces `prohibitHiddenPropertiesInQuery` setting at datasource/model + level to control if hidden/protected properties can be used in the `where` + object. By default, its value is `true`. For example, + {% include code-caption.html content="datasources/db.datasources.config.json" %} ```json { @@ -339,6 +379,7 @@ For example, } } ``` + With the following model definition: ```ts @@ -356,14 +397,16 @@ export class MyModel extends Entity { } ``` -`myModelRepository.find({where: {secret: 'guess'}});` will be sanitized as `myModelRepository.find({where: {}};` and a warning will be printed on the console: +`myModelRepository.find({where: {secret: 'guess'}});` will be sanitized as +`myModelRepository.find({where: {}};` and a warning will be printed on the +console: ```sh Potential security alert: hidden/protected properties ["secret"] are used in query. ``` -2. Reports circular references -If the filter object has circular references, LoopBack throws an error as follows: +2. Reports circular references If the filter object has circular references, + LoopBack throws an error as follows: ```js { @@ -372,12 +415,14 @@ If the filter object has circular references, LoopBack throws an error as follow code: 'QUERY_OBJECT_IS_CIRCULAR' } ``` -3. Constrains the maximum depth of query and data objects -Deep filter objects may be mapped to very complex queries that can potentially break your application. -To mitigate such risks, LoopBack allows you to configure `maxDepthOfQuery` and `maxDepthOfData` in datasource/model settings. The default value is `12`. Please note the `depth` is calculated based on the -level of child properties of an JSON object. -For example: -{% include code-caption.html content="datasources/db.datasources.config.json" %} + +3. Constrains the maximum depth of query and data objects Deep filter objects + may be mapped to very complex queries that can potentially break your + application. To mitigate such risks, LoopBack allows you to configure + `maxDepthOfQuery` and `maxDepthOfData` in datasource/model settings. The + default value is `12`. Please note the `depth` is calculated based on the + level of child properties of an JSON object. For example: + {% include code-caption.html content="datasources/db.datasources.config.json" %} ```json { @@ -389,7 +434,9 @@ For example: } } ``` -If the filter or data object exceeds the maximum depth, an error will be reported: + +If the filter or data object exceeds the maximum depth, an error will be +reported: ```js {