From 6902eefc945d44c983741d3f53fef91d9c1260cd Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Wed, 25 Mar 2020 16:40:40 -0400
Subject: [PATCH 1/8] docs: adding working with data pages

---
 docs/site/Fields-filter.md         |   7 +
 docs/site/Include-filter.md        |  10 +
 docs/site/Limit-filter.md          |  11 +
 docs/site/Order-filter.md          |  11 +
 docs/site/Querying-data.md         | 400 +++++++++++++++++++++++++++++
 docs/site/Skip-filter.md           |  10 +
 docs/site/Where-filter.md          |   8 +
 docs/site/Working-with-data.md     |  86 +++++++
 docs/site/sidebars/lb4_sidebar.yml |  34 +++
 9 files changed, 577 insertions(+)
 create mode 100644 docs/site/Fields-filter.md
 create mode 100644 docs/site/Include-filter.md
 create mode 100644 docs/site/Limit-filter.md
 create mode 100644 docs/site/Order-filter.md
 create mode 100644 docs/site/Querying-data.md
 create mode 100644 docs/site/Skip-filter.md
 create mode 100644 docs/site/Where-filter.md
 create mode 100644 docs/site/Working-with-data.md

diff --git a/docs/site/Fields-filter.md b/docs/site/Fields-filter.md
new file mode 100644
index 000000000000..04ade9600bd5
--- /dev/null
+++ b/docs/site/Fields-filter.md
@@ -0,0 +1,7 @@
+---
+title: 'Fields filter'
+lang: en
+keywords: LoopBack 4.0, LoopBack 4, fields
+sidebar: lb4_sidebar
+permalink: /doc/en/lb4/Fields-filter.html
+---
\ No newline at end of file
diff --git a/docs/site/Include-filter.md b/docs/site/Include-filter.md
new file mode 100644
index 000000000000..b28d03cf60bf
--- /dev/null
+++ b/docs/site/Include-filter.md
@@ -0,0 +1,10 @@
+---
+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
diff --git a/docs/site/Limit-filter.md b/docs/site/Limit-filter.md
new file mode 100644
index 000000000000..fa94054dd401
--- /dev/null
+++ b/docs/site/Limit-filter.md
@@ -0,0 +1,11 @@
+---
+title: 'Limit filter'
+lang: en
+keywords: LoopBack 4.0, LoopBack 4, limit
+layout: readme
+source: loopback-next
+file: packages/metadata/README.md
+sidebar: lb4_sidebar
+permalink: /doc/en/lb4/Limit-filter.html
+summary: A <i>limit</i> filter specifies a set of logical conditions to match, similar to a LIMIT clause in a SQL query.
+---
\ No newline at end of file
diff --git a/docs/site/Order-filter.md b/docs/site/Order-filter.md
new file mode 100644
index 000000000000..a773b89e2b15
--- /dev/null
+++ b/docs/site/Order-filter.md
@@ -0,0 +1,11 @@
+---
+title: 'Order filter'
+lang: en
+keywords: LoopBack 4.0, LoopBack 4, order
+layout: readme
+source: loopback-next
+file: packages/metadata/README.md
+sidebar: lb4_sidebar
+permalink: /doc/en/lb4/Order-filter.html
+summary: An <i>order</i> filter specifies a set of logical conditions to match, similar to a ORDER clause in a SQL query.
+--
\ No newline at end of file
diff --git a/docs/site/Querying-data.md b/docs/site/Querying-data.md
new file mode 100644
index 000000000000..8683ce1fe4a7
--- /dev/null
+++ b/docs/site/Querying-data.md
@@ -0,0 +1,400 @@
+---
+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.
+
+<table>
+  <thead>
+    <tr>
+      <th>Query</th>
+      <th>Model API (Node)</th>
+      <th>REST API</th>
+    </tr>
+  </thead>
+  <tbody>    
+    <tr>
+      <td>
+        Find all model instances using specified filters.
+      </td>
+      <td>
+        <code><a href="https://apidocs.loopback.io/loopback/#persistedmodel-find" class="external-link">find(filter, callback)</a></code>
+        Where filter is a JSON object containing the query filters.
+        See <a href="Querying-data.html">Filters</a> below.
+      </td>
+      <td>
+         <code>GET /<em>modelName</em>?filter...</code>
+        See <a href="PersistedModel-REST-API.html#find-matching-instances">Model REST API - Find matching instances</a>.
+        <span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span>
+      </td>
+    </tr>
+    <tr>
+      <td>Find first model instance using specified filters.</td>
+      <td>
+        <code><a href="https://apidocs.loopback.io/loopback/#persistedmodel-findone" class="external-link">findOne(filter, callback)</a></code>
+        Where filter is a JSON object containing the query filters.
+        <span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span>
+      </td>
+      <td>
+        <code><span>GET /<em>modelName</em>/findOne?filter...</span></code>
+        See <a href="PersistedModel-REST-API.html#find-first-instance">Model REST API - Find first instance</a>.
+        <span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span>
+      </td>
+    </tr>
+    <tr>
+      <td>Find instance by ID.</td>
+      <td>
+        <code><a href="https://apidocs.loopback.io/loopback/#persistedmodel-findbyid" class="external-link">findById(id, [filter,] callback)</a></code>
+        Where optional filter is a JSON object <span>containing the query filters.</span>
+        <span><span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span></span>
+
+      </td>
+      <td>
+        <code><span>GET /</span><em>modelName</em><span>/</span><em>modelID</em></code>
+        See <a href="PersistedModel-REST-API.html#find-instance-by-id">Model REST API - Find instance by ID</a>.
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+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:
+
+* [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)
+
+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:
+
+<table>
+  <thead>
+    <tr>
+      <th>Filter type</th>
+      <th>Type</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>fields</td>
+      <td>Object, Array, or String</td>
+      <td>
+        Specify fields to include in or exclude from the response.
+        See <a href="Fields-filter.html">Fields filter</a>.
+      </td>
+    </tr>
+    <tr>
+      <td>include</td>
+      <td>String, Object, or Array</td>
+      <td>
+        Include results from related models, for relations such as <em>belongsTo</em> and <em>hasMany</em>.
+        See <a href="Include-filter.html">Include filter</a>.
+      </td>
+    </tr>
+    <tr>
+      <td>limit</td>
+      <td>Number</td>
+      <td>
+        Limit the number of instances to return.
+        See <a href="Limit-filter.html">Limit filter</a>.
+      </td>
+    </tr>
+    <tr>
+      <td>order</td>
+      <td>String</td>
+      <td>
+        Specify sort order: ascending or descending.
+        See <a href="Order-filter.html">Order filter</a>.
+      </td>
+    </tr>
+    <tr>
+      <td>skip (offset)</td>
+      <td>Number</td>
+      <td>
+        Skip the specified number of instances.
+        See <a href="Skip-filter.html">Skip filter</a>.
+      </td>
+    </tr>
+    <tr>
+      <td>where</td>
+      <td>Object</td>
+      <td>
+        Specify search criteria; similar to a WHERE clause in SQL.
+        See <a href="Where-filter.html">Where filter</a>.
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+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});
+```
+
+Equivalent using REST:
+
+`/accounts?filter[where][name]=John&filter[limit]=3`
+
+## Syntax
+
+In both Node.js API and REST, you can use any number of filters to define a query.
+
+### REST syntax
+
+Specify filters in the [HTTP query string](http://en.wikipedia.org/wiki/Query_string):
+
+`/modelName?filter=[filterType1]=val1&filter[filterType2]=val2...`
+
+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.
+
+{% 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
+
+Specify filters as the first argument to `find()` and `findOne()`: 
+
+```javascript
+{ 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.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.
+
+### 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:
+
+`?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 (").
+
+{% 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: `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. 
+
+For example, you can build the filter
+
+```ts
+const filter = {
+  where: {id: 3},
+  include: [{relation: 'orders', scope: {where: {name: 'toy'}}]
+};
+```
+with the `FilterBuilder`:
+
+```ts
+import FilterBuilder from '@loopback/repository';
+...
+const filterBuilder = new FilterBuilder();
+    filterBuilder
+    .include(
+      {relation: 'orders', scope: {where: {name: 'ray'}}},
+    )
+    .where({id:3})
+    .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,
+
+```ts
+const filter = new FilterBuilder()
+  .limit(5)
+  .where({id: 101});
+filter.impose({where: {id: 999, name: 'LoopBack'}});
+```
+
+The `where` clauses is combined as:
+
+```ts
+{
+  limit: 5,
+  where: {
+      and: [{id: 101}, {id: 999, name: 'LoopBack'}],
+  }
+}
+```
+
+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.
+
+<!-- TODO: (Agnes) need to double check. 
+### Filtering nested properties
+
+LoopBack supports filtering nested properties in three NoSQL connectors: MongoDB, Cloudant, and memory.
+For example, model `User` contains a nested property `user.address.tags.tag`:
+```javascript
+db.define('User', {
+  name: {type: String, index: true},
+  email: {type: String, index: true},
+  address: {
+    street: String,
+    city: String,
+    tags: [
+      {
+        tag: String,
+      }
+    ]
+  }
+});
+```
+users can do a nested query like `User.find({where: {'address.tags.tag': 'business'}}`.
+Data source connectors for relational databases don't support filtering nested properties. -->
+
+### Sanitizing filter and data objects
+
+<!-- TODO: (Agnes) need to double check. 
+
+Filters are very powerful and flexible. To prevent them from creating potential security risks,
+LoopBack sanitizes filter objects as follows:
+1. Normalizes `undefined` values
+The policy is controlled by the `normalizeUndefinedInQuery` setting at datasource or model
+level. There are three options:
+- 'nullify': Set `undefined` to `null`
+- 'throw': Throw an error if `undefined` is found
+- 'ignore': Remove `undefined`. This is the default behavior if `normalizeUndefinedInQuery`
+  is not configured
+For example:
+{% include code-caption.html content="datasources/db.datasources.config.json" %}
+
+```json
+{
+  "db": {
+    "name": "db",
+    "connector": "memory",
+    "normalizeUndefinedInQuery": "ignore"
+  }
+}
+```
+
+{% include code-caption.html content="server/model-config.json" %}
+
+```json
+{
+  "project": {
+    "dataSource": "db",
+    "public": true,
+    "normalizeUndefinedInQuery": "throw"
+  }
+}
+``` -->
+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" %}
+
+```json
+{
+  "db": {
+    "name": "db",
+    "connector": "memory",
+    "prohibitHiddenPropertiesInQuery": true
+  }
+}
+```
+With the following model definition:
+
+```ts
+@model(
+settings:{hidden:['secret']}}
+)
+export class MyModel extends Entity {
+  // other props
+
+  @property({
+    type: 'string',
+  })
+  secret?: string;
+  //...
+}
+```
+
+`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:
+
+```js
+{
+  message: 'The query object is circular',
+  statusCode: 400,
+  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" %}
+
+```json
+{
+  "db": {
+    "name": "db",
+    "connector": "memory",
+    "maxDepthOfQuery": 5,
+    "maxDepthOfData": 16
+  }
+}
+```
+If the filter or data object exceeds the maximum depth, an error will be reported:
+
+```js
+{
+  message: 'The query object exceeds maximum depth 5',
+  statusCode: 400,
+  code: 'QUERY_OBJECT_TOO_DEEP'
+}
+```
diff --git a/docs/site/Skip-filter.md b/docs/site/Skip-filter.md
new file mode 100644
index 000000000000..3796510e6113
--- /dev/null
+++ b/docs/site/Skip-filter.md
@@ -0,0 +1,10 @@
+---
+title: 'Skip filter'
+lang: en
+keywords: LoopBack 4.0, LoopBack 4, skip
+layout: readme
+source: loopback-next
+file: packages/metadata/README.md
+sidebar: lb4_sidebar
+permalink: /doc/en/lb4/Skip-filter.html
+---
\ No newline at end of file
diff --git a/docs/site/Where-filter.md b/docs/site/Where-filter.md
new file mode 100644
index 000000000000..db818c0ed04e
--- /dev/null
+++ b/docs/site/Where-filter.md
@@ -0,0 +1,8 @@
+---
+title: 'Where filter'
+lang: en
+keywords: LoopBack 4.0, LoopBack 4, where
+sidebar: lb4_sidebar
+permalink: /doc/en/lb4/Where-filter.html
+summary: A <i>where</i> filter specifies a set of logical conditions to match, similar to a WHERE clause in a SQL query.
+---
\ No newline at end of file
diff --git a/docs/site/Working-with-data.md b/docs/site/Working-with-data.md
new file mode 100644
index 000000000000..4e62e15a4ceb
--- /dev/null
+++ b/docs/site/Working-with-data.md
@@ -0,0 +1,86 @@
+---
+lang: en
+title: 'Working with data'
+keywords: LoopBack 4.0, LoopBack 4
+sidebar: lb4_sidebar
+permalink: /doc/en/lb4/Working-with-data.html
+summary: --
+---
+
+In LoopBack 4, models describe the shape of data, repositories provide behavior
+like CRUD operations, and controllers define routes (this is different from
+LoopBack 3.x where models implement behavior too). LB4
+[repositories](Repository.md) provide a couple of create, read, update, and
+delete (CRUD) operations. Once you have defined these three artifacts, you can
+add data to the model, manipulate the data, and query it through these CRUD
+operations. The following is an overview of CRUD operations at different levels:
+
+<table>
+  <thead>
+    <tr>
+      <th width="120">Operation</th>
+      <th width="360"><a href="https://loopback.io/doc/en/lb4/Routes.html">REST</a></th>
+      <th width="300">LoopBack model method<br>(Node.js API)&#42;</th>
+      <th width="120">Corresponding SQL<br>Operation</th>
+    </tr>
+  </thead>
+  <tbody>    
+    <tr>
+      <td>Create</td>
+      <td>
+        PUT /<em>modelName</em>
+        <br/>POST /<em>modelName</em>
+      </td>
+      <td><code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.create.html" class="external-link" rel="nofollow">create()</a></code>
+      <br/><code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.createall.html" class="external-link" rel="nofollow">createAll()</a></code>
+      </td>
+      <td>INSERT</td>
+    </tr>
+    <tr>
+      <td>Read (Retrieve)</td>
+      <td>GET /<em>modelName</em>?filter=...</td>
+      <td><code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.find.html" class="external-link" rel="nofollow">find<sup>&#42;</sup>()</a></code>
+      </td>
+      <td>SELECT</td>
+    </tr>
+    <tr>
+      <td>Update (Modify)</td>
+      <td>
+        POST /<em>modelName</em>
+        <br/>PUT /<em>modelName</em>
+      </td>
+      <td><code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.update.html" class="external-link" rel="nofollow">update<sup>&#42;</sup>()</a></code>
+      <br/><code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.replacebyid.html" class="external-link" rel="nofollow">replaceById()</a></code>
+      </td>
+      <td>UPDATE</td>
+    </tr>
+    <tr>
+      <td>Delete (Destroy)</td>
+      <td>DELETE /<em>modelName</em>/<em>modelID</em></td>
+      <td><code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.delete.html" class="external-link" rel="nofollow">delete<sup>&#42;</sup>()</a></code>
+      </td>
+      <td>DELETE</td>
+    </tr>
+  </tbody>
+</table>
+
+(\*) Methods listed are just prominent examples; other methods may provide
+similar functionality; for example: `findById()`, `findOne()`,
+and `updateAll()`.  See
+[DefaultCrudRepository Methods API documentation](https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.html#methods)
+for more information.
+
+See the following articles for more information:
+
+- [Creating, updating, and deleting data](Creating-updating-and-deleting-data.html)
+- [Querying data](Querying-data.html)
+  - [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)
+- [Using database transactions](Using-database-transactions.html)
+- [Realtime server-sent events](Realtime-server-sent-events.html)
+
+{% include content/angular-methods-caveat.html lang=page.lang %}
diff --git a/docs/site/sidebars/lb4_sidebar.yml b/docs/site/sidebars/lb4_sidebar.yml
index e8a401e3b5d0..23e747d88537 100644
--- a/docs/site/sidebars/lb4_sidebar.yml
+++ b/docs/site/sidebars/lb4_sidebar.yml
@@ -571,6 +571,40 @@ children:
     url: Copyright-generator.html
     output: 'web, pdf'
 
+- title: 'Working with data'
+  url: Working-with-data.html
+  output: 'web, pdf'
+  children:
+
+  - title: 'Querying data'
+  url: Querying-data.html
+  output: 'web, pdf'
+  children:
+
+  - title: 'Fields filter'
+    url: Fields-filter.html
+    output: 'web, pdf'
+
+  - title: 'Include filter'
+    url: Include-filter.html
+    output: 'web, pdf'
+
+  - title: 'Limit filter'
+    url: Limit-filter.html
+    output: 'web, pdf'
+
+  - title: 'Order filter'
+    url: Order-filter.html
+    output: 'web, pdf'
+
+  - title: 'Skip filter'
+    url: Skip-filter.html
+    output: 'web, pdf'
+
+  - title: 'Where filter'
+    url: Where-filter.html
+    output: 'web, pdf'
+
 - title: 'Connectors reference'
   url: Connectors-reference.html
   output: 'web'

From edc080abd483f8a2927e0dfea1c6e142b5e94d08 Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Fri, 27 Mar 2020 10:08:28 -0400
Subject: [PATCH 2/8] docs: order filter

---
 docs/site/Order-filter.md | 82 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 5 deletions(-)

diff --git a/docs/site/Order-filter.md b/docs/site/Order-filter.md
index a773b89e2b15..efd9da362d71 100644
--- a/docs/site/Order-filter.md
+++ b/docs/site/Order-filter.md
@@ -2,10 +2,82 @@
 title: 'Order filter'
 lang: en
 keywords: LoopBack 4.0, LoopBack 4, order
-layout: readme
-source: loopback-next
-file: packages/metadata/README.md
 sidebar: lb4_sidebar
 permalink: /doc/en/lb4/Order-filter.html
-summary: An <i>order</i> filter specifies a set of logical conditions to match, similar to a ORDER clause in a SQL query.
---
\ No newline at end of file
+summary:
+  An <i>order</i> filter specifies a set of logical conditions to match, similar
+  to a ORDER clause in a SQL query.
+---
+
+An *order* filter specifies how to sort the results: ascending (ASC) or
+descending (DESC) based on the specified property.
+
+### Node.js API
+
+{% include content/angular-methods-caveat.html lang=page.lang %}
+
+Order by one property:
+
+<pre>
+{order: '<i>propertyName</i> <ASC|DESC>'}
+</pre>
+
+Order by two or more properties:
+
+<pre>
+{order: ['<i>propertyName</i> <ASC|DESC>', '<i>propertyName</i> <ASC|DESC>',...]}
+</pre>
+
+Where:
+
+- *propertyName* is the name of the property (field) to sort by.
+- `<ASC|DESC>` signifies either ASC for ascending order or DESC for descending
+  order.
+
+### REST API
+
+Order by one property:
+
+<pre>
+?filter[order]=<i>propertyName<i>%20<ASC|DESC>
+</pre>
+
+Order by two or more properties:
+
+<pre>
+?filter[order][0]=<i>propertyName</i> <ASC|DESC>&filter[order][1]=<i>propertyName</i> <ASC|DESC>...
+</pre>
+
+Where:
+
+- *propertyName* is the name of the property (field) to sort by.
+- `<ASC|DESC>` signifies either ASC for ascending order or DESC for descending
+  order.
+
+You can also
+use [stringified JSON format](Querying-data.html#using-stringified-json-in-rest-queries) in
+a REST query.
+
+{% include note.html content="Configure default ordering in [default scope](Model-definition-JSON-file.html#default-scope).
+" %}
+
+### Examples
+
+Return the three most expensive items, sorted by the `price` property:
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await itemRepository.find({
+  order: 'price DESC',
+  limit: 3,
+});
+```
+
+{% include code-caption.html content="REST" %}
+
+`/items?filter[order]=price%20DESC&filter[limit]=3`
+
+Or stringified JSON format:
+
+`/items?filter={"order":["price DESC"],"limit":3}`

From 57b487a6a4ada3426b9841c4f054153a21d59fd0 Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Fri, 27 Mar 2020 11:03:04 -0400
Subject: [PATCH 3/8] docs: fields filter

---
 docs/site/Fields-filter.md | 97 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/docs/site/Fields-filter.md b/docs/site/Fields-filter.md
index 04ade9600bd5..44eb4a6d39e7 100644
--- a/docs/site/Fields-filter.md
+++ b/docs/site/Fields-filter.md
@@ -4,4 +4,99 @@ lang: en
 keywords: LoopBack 4.0, LoopBack 4, fields
 sidebar: lb4_sidebar
 permalink: /doc/en/lb4/Fields-filter.html
----
\ No newline at end of file
+---
+
+A _fields_ filter specifies properties (fields) to include or exclude from the
+results.
+
+### Node.js API
+
+{% 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.
+
+### 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...`
+
+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.

From a640b21701a8b6f8d9f744f8b8103c0c616e49bb Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Fri, 27 Mar 2020 13:13:49 -0400
Subject: [PATCH 4/8] docs: fix limit

---
 docs/site/Limit-filter.md | 47 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 5 deletions(-)

diff --git a/docs/site/Limit-filter.md b/docs/site/Limit-filter.md
index fa94054dd401..665ef6911ca5 100644
--- a/docs/site/Limit-filter.md
+++ b/docs/site/Limit-filter.md
@@ -2,10 +2,47 @@
 title: 'Limit filter'
 lang: en
 keywords: LoopBack 4.0, LoopBack 4, limit
-layout: readme
-source: loopback-next
-file: packages/metadata/README.md
 sidebar: lb4_sidebar
 permalink: /doc/en/lb4/Limit-filter.html
-summary: A <i>limit</i> filter specifies a set of logical conditions to match, similar to a LIMIT clause in a SQL query.
----
\ No newline at end of file
+summary:
+  A <i>limit</i> filter specifies a set of logical conditions to match, similar
+  to a LIMIT clause in a SQL query.
+---
+
+A *limit* filter limits the maximum number of records a query returns.
+
+{% include content/angular-methods-caveat.html lang=page.lang %}
+
+### Node.js API
+
+<pre>
+{ limit: <i>n</i> }
+</pre>
+
+Where *n* is the maximum number of results (records) to return.
+
+### REST API
+
+<pre>
+filter[limit]=<i>n</i>
+</pre>
+
+You can also
+use [stringified JSON format](Querying-data.html#using-stringified-json-in-rest-queries) in
+a REST query.
+
+### Examples
+
+Return only the first five query results:
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await orderRepository.find({limit: 5});
+```
+
+{% include code-caption.html content="REST" %}
+
+`/orders?filter[limit]=5`
+
+Or stringified JSON format: `/orders?filter={"limit":5}`

From e32ef9893816be6b1a9e077acd213708a8733084 Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Fri, 27 Mar 2020 14:16:05 -0400
Subject: [PATCH 5/8] 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.
 
 <table>
   <thead>
@@ -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.
       </td>
       <td>
-        <code><a href="https://apidocs.loopback.io/loopback/#persistedmodel-find" class="external-link">find(filter, callback)</a></code>
+        <code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.find.html" class="external-link">find(filter, options?)</a></code>
         Where filter is a JSON object containing the query filters.
-        See <a href="Querying-data.html">Filters</a> below.
       </td>
       <td>
          <code>GET /<em>modelName</em>?filter...</code>
-        See <a href="PersistedModel-REST-API.html#find-matching-instances">Model REST API - Find matching instances</a>.
-        <span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span>
       </td>
     </tr>
     <tr>
       <td>Find first model instance using specified filters.</td>
       <td>
-        <code><a href="https://apidocs.loopback.io/loopback/#persistedmodel-findone" class="external-link">findOne(filter, callback)</a></code>
+        <code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.findone.html" class="external-link">findOne(filter, options?)</a></code>
         Where filter is a JSON object containing the query filters.
-        <span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span>
       </td>
       <td>
         <code><span>GET /<em>modelName</em>/findOne?filter...</span></code>
-        See <a href="PersistedModel-REST-API.html#find-first-instance">Model REST API - Find first instance</a>.
-        <span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span>
       </td>
     </tr>
     <tr>
       <td>Find instance by ID.</td>
       <td>
-        <code><a href="https://apidocs.loopback.io/loopback/#persistedmodel-findbyid" class="external-link">findById(id, [filter,] callback)</a></code>
+        <code><a href="https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.findbyid.html" class="external-link">findById(id, filter?, options?)</a></code>
         Where optional filter is a JSON object <span>containing the query filters.</span>
-        <span><span>See </span><a href="Querying-data.html">Filters</a> <span> below.</span></span>
-
       </td>
       <td>
         <code><span>GET /</span><em>modelName</em><span>/</span><em>modelID</em></code>
-        See <a href="PersistedModel-REST-API.html#find-instance-by-id">Model REST API - Find instance by ID</a>.
       </td>
     </tr>
   </tbody>
 </table>
 
-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:
   </thead>
   <tbody>
     <tr>
-      <td>fields</td>
+      <td><code>fields</code></td>
       <td>Object, Array, or String</td>
       <td>
         Specify fields to include in or exclude from the response.
@@ -104,7 +103,7 @@ The following table describes LoopBack's filter types:
       </td>
     </tr>
     <tr>
-      <td>include</td>
+      <td><code>include</code></td>
       <td>String, Object, or Array</td>
       <td>
         Include results from related models, for relations such as <em>belongsTo</em> and <em>hasMany</em>.
@@ -112,7 +111,7 @@ The following table describes LoopBack's filter types:
       </td>
     </tr>
     <tr>
-      <td>limit</td>
+      <td><code>limit</code></td>
       <td>Number</td>
       <td>
         Limit the number of instances to return.
@@ -120,7 +119,7 @@ The following table describes LoopBack's filter types:
       </td>
     </tr>
     <tr>
-      <td>order</td>
+      <td><code>order</code></td>
       <td>String</td>
       <td>
         Specify sort order: ascending or descending.
@@ -128,7 +127,7 @@ The following table describes LoopBack's filter types:
       </td>
     </tr>
     <tr>
-      <td>skip (offset)</td>
+      <td><code>skip</code> (offset)</td>
       <td>Number</td>
       <td>
         Skip the specified number of instances.
@@ -136,7 +135,7 @@ The following table describes LoopBack's filter types:
       </td>
     </tr>
     <tr>
-      <td>where</td>
+      <td><code>where</code></td>
       <td>Object</td>
       <td>
         Specify search criteria; similar to a WHERE clause in SQL.
@@ -146,7 +145,8 @@ The following table describes LoopBack's filter types:
   </tbody>
 </table>
 
-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=<encodeResult>`
 
-* _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.
 
-<!-- TODO: (Agnes) need to double check. 
+<!-- TODO: (Agnes) need to double check.
 ### Filtering nested properties
 
 LoopBack supports filtering nested properties in three NoSQL connectors: MongoDB, Cloudant, and memory.
@@ -287,7 +326,7 @@ Data source connectors for relational databases don't support filtering nested p
 
 ### Sanitizing filter and data objects
 
-<!-- TODO: (Agnes) need to double check. 
+<!-- TODO: (Agnes) need to double check.
 
 Filters are very powerful and flexible. To prevent them from creating potential security risks,
 LoopBack sanitizes filter objects as follows:
@@ -322,13 +361,14 @@ For example:
   }
 }
 ``` -->
+
 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
 {

From b9084fdb373b1e4c52c0d6c577f6b14920db14e3 Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Fri, 27 Mar 2020 15:23:15 -0400
Subject: [PATCH 6/8] docs: skip filter

---
 docs/site/Skip-filter.md | 71 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 67 insertions(+), 4 deletions(-)

diff --git a/docs/site/Skip-filter.md b/docs/site/Skip-filter.md
index 3796510e6113..6858d02f9362 100644
--- a/docs/site/Skip-filter.md
+++ b/docs/site/Skip-filter.md
@@ -2,9 +2,72 @@
 title: 'Skip filter'
 lang: en
 keywords: LoopBack 4.0, LoopBack 4, skip
-layout: readme
-source: loopback-next
-file: packages/metadata/README.md
 sidebar: lb4_sidebar
 permalink: /doc/en/lb4/Skip-filter.html
----
\ No newline at end of file
+---
+
+A skip filter omits the specified number of returned records. This is useful,
+for example, to paginate responses.
+
+Use `offset` as an alias for `skip`.
+
+{% include content/angular-methods-caveat.html lang=page.lang %}
+
+### Node.js
+
+<pre>
+{skip: <i>n</i>}
+</pre>
+
+Where _n_ is the number of records to skip.
+
+### REST API
+
+<pre>
+?filter[skip]=<i>n</i>
+</pre>
+
+You can also
+use [stringified JSON format](Querying-data.md#using-stringified-json-in-rest-queries) in
+a REST query.
+
+### Examples
+
+To Skip the first three records:
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await orderRepository.find({skip: 3});
+```
+
+{% include code-caption.html content="REST" %}
+
+`/orders?filter[skip]=3`
+
+Or stringified JSON format:
+
+`/orders?filter={"skip":3}`
+
+**Pagination Example**
+
+The following requests illustrate how to paginate a query result. Each request
+request returns ten records: the first returns the first ten, the second returns
+the 11th through the 20th, and so on...
+
+{% include code-caption.html content="REST" %}
+
+```
+/orders?filter[limit]=10&filter[skip]=0
+/orders?filter[limit]=10&filter[skip]=10
+/orders?filter[limit]=10&filter[skip]=20
+...
+```
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await orderRepository.find({limit: 10, skip: 0});
+await orderRepository.find({limit: 10, skip: 10});
+await orderRepository.find({limit: 10, skip: 20});
+```

From 0d537d2701020df9adeb4afebf5dcf25f0ef691f Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Fri, 27 Mar 2020 17:10:36 -0400
Subject: [PATCH 7/8] docs: include filter

---
 docs/site/Include-filter.md | 271 +++++++++++++++++++++++++++++++++++-
 1 file changed, 267 insertions(+), 4 deletions(-)

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=<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
+
+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).

From eb722d16f557e8da412cdfd3eaa0bf9610e1da09 Mon Sep 17 00:00:00 2001
From: Agnes Lin <agneslin.lin@ibm.com>
Date: Tue, 31 Mar 2020 18:35:03 -0400
Subject: [PATCH 8/8] docs: where filter

---
 docs/site/Where-filter.md | 685 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 683 insertions(+), 2 deletions(-)

diff --git a/docs/site/Where-filter.md b/docs/site/Where-filter.md
index db818c0ed04e..d26de6db6609 100644
--- a/docs/site/Where-filter.md
+++ b/docs/site/Where-filter.md
@@ -4,5 +4,686 @@ lang: en
 keywords: LoopBack 4.0, LoopBack 4, where
 sidebar: lb4_sidebar
 permalink: /doc/en/lb4/Where-filter.html
-summary: A <i>where</i> filter specifies a set of logical conditions to match, similar to a WHERE clause in a SQL query.
----
\ No newline at end of file
+summary:
+  A <i>where</i> filter specifies a set of logical conditions to match, similar
+  to a WHERE clause in a SQL query.
+---
+
+## REST API
+
+In the first form below, the condition is equivalence, that is, it checks
+whether *property* equals *value*. The second form below is for all other
+conditions.
+
+```
+filter[where][property]=value
+```
+
+```
+filter[where][property][op]=value
+```
+
+Where:
+
+- *property* is the name of a property (field) in the model being queried.
+- *value* is a literal value.
+- *op* is one of the [operators](#operators) listed below.
+
+For example, if there is a `Car` model with an `odo` property, the following
+query finds instances where the `odo` is greater than 5000:
+
+```
+/cars?filter[where][odo][gt]=5000
+```
+
+For example, here is a query to find cars with `odo` is less than 30,000:
+
+```
+/cars?filter[where][odo][lt]=30000
+```
+
+You can also
+use [stringified JSON format](Querying-data.html#using-stringified-json-in-rest-queries) in
+a REST query. The above example can be written as:
+
+```
+/cars?filter={"where":{"odo":{"lt":30000}}}
+```
+
+### Filter limit
+
+{% include important.html content="There is a limit of twenty filters (combined with AND or OR) using this format, due to the use of [qs](https://github.com/ljharb/qs#parsing-arrays).  When there are more than twenty, the filter is converted into an `Object` where it is expecting
+an `Array`. See [LoopBack issue #2824](https://github.com/strongloop/loopback/issues/2824) for more details.
+" %}
+
+You can encode the large filter object as "stringified JSON":
+
+```
+http://localhost:3000/api/Books
+?filter={"where":{"or":[{"id":1},{"id":2},...,{"id":20"},{"id":21}]}}
+```
+
+<!-- DOES NOT WORK IN LB4
+We might want something similar for LB4
+
+**Override limit in `server.js`**
+
+```js
+// In `server/server.js`, before boot is called
+var loopback = require('loopback');
+var boot = require('loopback-boot');
+var qs = require('qs');
+
+var app = module.exports = loopback();
+app.set('query parser', function(value, option) {
+  return qs.parse(value, {arrayLimit: 500});
+});
+
+app.start = function() {
+  ...
+``` -->
+
+## Node.js API
+
+{% include content/angular-methods-caveat.html lang=page.lang %}
+
+### Where clause for queries
+
+For query methods such as `find()` or `findOne()`, use the first form below to
+check equivalence, that is, whether *property* equals *value*. Use the second
+form below for all other conditions.
+
+```ts
+{
+  where: {
+    property: value;
+  }
+}
+```
+
+```ts
+{
+  where: {
+    property: {
+      op: value;
+    }
+  }
+}
+```
+
+Where:
+
+- *property* is the name of a property (field) in the model being queried.
+- *value* is a literal value.
+- *op* is one of the [operators](#operators) listed below.
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await productRepository.find({where: {size: 'large'}});
+```
+
+{% include code-caption.html content="REST" %}
+
+`/products?filter[where][size]=large`
+
+{% include tip.html content="The above where clause syntax is for queries, and not for [`count()`](https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.count.html).
+For all other methods, including `count()`, omit the `{ where : ... }` wrapper; see [Where clause for other methods](#where-clause-for-other-methods) below.
+" %}
+
+### Where clause for other methods
+
+{% include important.html content="When you call the Node.js APIs _for methods other than queries_, that is for methods that update and delete
+(and [`count()`](https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.count.html)), don't wrap the where clause in a `{ where : ... }` object, simply use the condition as the argument. See examples below.
+" %}
+
+In the first form below, the condition is equivalence, that is, it checks
+whether *property* equals *value*. The second form is for all other conditions.
+
+```ts
+{
+  property: value;
+}
+```
+
+```ts
+{
+  property: {
+    op: value;
+  }
+}
+```
+
+Where:
+
+- *property* is the name of a property (field) in the model being queried.
+- *value* is a literal value.
+- *op* is one of the [operators](#operators) listed below.
+
+For example, a where clause in a call to a
+model's [updateAll()](https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.updateall.html) method.
+Note the lack of `{ where : ... }` in the argument.
+
+```ts
+await orderRepository.updateAll({id: 123}, {customerId: null});
+```
+
+More examples, this time in a call
+to [deleteAll()](https://loopback.io/doc/en/lb4/apidocs.repository.defaultcrudrepository.deleteall.html):
+
+```ts
+await orderRepository.deleteAll({customerId: 99});
+```
+
+To delete all records where the cost property is greater than 100:
+
+```ts
+await productRepositor.deleteAll({cost: {gt: 100}});
+```
+
+### Default scope with where filters
+
+Adding a `scope` to a [model definition](Model.md#scope)) automatically adds a
+method to model. LoopBack will apply the filter whenever a model is created,
+updated, or queried.
+
+{% include tip.html content="scope with a `where` filter may not work as you expect!
+" %}
+
+## Operators
+
+This table describes the operators available in "where" filters.
+See [Examples](#examples) below.
+
+| Operator                | Description                                                                                                                                                                                                                                                                                                                                        |
+| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| eq                      | Equivalence. See [examples](#equivalence) below.                                                                                                                                                                                                                                                                                                   |
+| and                     | Logical AND operator. See [AND and OR operators](#and-and-or-operators) and [examples](#and--or) below.                                                                                                                                                                                                                                            |
+| or                      | Logical OR operator. See [AND and OR operators](#and-and-or-operators) and [examples](#and--or) below.                                                                                                                                                                                                                                             |
+| gt, gte                 | Numerical greater than (&gt;); greater than or equal (&gt;=). Valid only for numerical and date values. See [examples](#gt-and-lt) below. <br/><br/> For Geopoint values, the units are in miles by default. See [Geopoint](http://apidocs.loopback.io/loopback-datasource-juggler/#geopoint) for more information.                                |
+| lt, lte                 | Numerical less than (&lt;); less than or equal (&lt;=). Valid only for numerical and date values. <br/><br/>For geolocation values, the units are in miles by default. See [Geopoint](http://apidocs.loopback.io/loopback-datasource-juggler/#geopoint) for more information.                                                                      |
+| between                 | True if the value is between the two specified values: greater than or equal to first value and less than or equal to second value. See [examples](#gt-and-lt) below. <br/><br/> For geolocation values, the units are in miles by default. See [Geopoint](http://apidocs.loopback.io/loopback-datasource-juggler/#geopoint) for more information. |
+| inq, nin                | In / not in an array of values. See [examples](#inq) below.                                                                                                                                                                                                                                                                                        |
+| near                    | For geolocations, return the closest points, sorted in order of distance. Use with `limit` to return the _n_ closest points. See [examples](#near) below.                                                                                                                                                                                          |
+| neq                     | Not equal (!=)                                                                                                                                                                                                                                                                                                                                     |
+| like, nlike             | LIKE / NOT LIKE operators for use with regular expressions. The regular expression format depends on the backend data source. See [examples](#like-and-nlike) below.                                                                                                                                                                               |
+| like, nlike, options: i | LIKE / NOT LIKE operators for use with regular expressions with the case insensitive flag. It is supported by the memory and MongoDB connectors. The options property set to 'i' tells LoopBack that it should do case-insensitive matching on the required property. See [examples](#like-and-nlike-insensitive) below.                           |
+| ilike, nilike           | ILIKE / NOT ILIKE operators for use with regular expressions. The operator is supported only by the memory and Postgresql connectors. See [examples](#ilike-and-nilike) below.                                                                                                                                                                     |
+| regexp                  | Regular expression. See [examples](#regular-expressions) below.                                                                                                                                                                                                                                                                                    |
+
+### AND and OR operators
+
+Use the AND and OR operators to create compound logical filters based on simple
+where filter conditions, using the following syntax.
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+{where: {<and|or>: [condition1, condition2, ...]}}
+```
+
+{% include code-caption.html content="REST" %}
+
+`[where][<and|or>][0]condition1&[where][<and|or>]condition2...`
+
+Where _condition1_ and *condition2* are a filter conditions.
+
+See [examples](#examples) below.
+
+### Regular expressions
+
+You can use regular expressions in a where filter, with the following syntax.
+You can use a regular expression in a where clause for updates and deletes, as
+well as queries.
+
+Essentially, `regexp` is just like an operator in which you provide a regular
+expression value as the comparison value.
+
+{% include tip.html content="A regular expression value can also include one or more [flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags).  For example, append `/i` to the regular expression to perform a case-insensitive match.
+" %}
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+{where: {property: {regexp: <expression>}}}
+```
+
+Where `<expression>` can be a:
+
+- String defining a regular expression (for example, `'^foo'` ).
+- Regular expression literal (for example, `/^foo/` ).
+- Regular expression object (for example, `new RegExp(/John/)`).
+
+Or, in a simpler format:
+
+```ts
+{where: {property: <expression>}}}
+```
+
+Where `<expression>` can be a:
+
+- Regular expression literal (for example, `/^foo/` ).
+- Regular expression object (for example, `new RegExp(/John/)`).
+
+For more information on JavaScript regular expressions,
+see [Regular Expressions (Mozilla Developer Network)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions).
+
+{% include tip.html content="The above where clause syntax is for queries.
+For updates and deletes, omit the `{ where : ... }` wrapper.
+See [Where clause for other methods](#where-clause-for-other-methods) below.
+" %}
+
+For example, this query returns all products for which the category starts with
+a capital "T":
+
+```ts
+await productRepository.find({where: {category: {regexp: '^T'}}});
+```
+
+Or, using the simplified form:
+
+```ts
+await productRepository.find({where: {category: /^T/}});
+```
+
+{% include code-caption.html content="REST" %}
+
+`filter[where][property][regexp]=expression`
+
+Where:
+
+- *property* is the name of a property (field) in the model being queried.
+- *expression* is the JavaScript regular expression string.
+  See [Regular Expressions (Mozilla Developer Network)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions).
+
+A regular expression value can also include one or
+more [flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags).
+For example, append `/i` to the regular expression to perform a case-insensitive
+match.
+
+{% include important.html content="When using a regular expression flag with the REST API,
+you _must_ precede the regular expression with a slash character (`/`).
+" %}
+
+The following REST query returns all products for which the category starts with
+a capital "T"::
+
+```
+/api/products?filter[where][category][regexp]=^T
+```
+
+The following REST query returns products that start with either an uppercase
+"T" or lowercase "t":
+
+```
+/api/products?filter[where][category][regexp]=/^t/i
+```
+
+Note that since the regular expression includes a flag, it is preceded by a
+slash (`/`).
+
+## Examples
+
+### Equivalence
+
+Weapons with name M1911:
+
+{% include code-caption.html content="REST" %}
+
+`/weapons?filter[where][name]=M1911`
+
+Or stringified JSON format:
+
+`/weapons?filter={"where":{"name::"M1911"}}`
+
+Products where size is "large":
+
+{% include code-caption.html content="REST" %}
+
+`/products?filter[where][size]=large` `/products?filter[where][size][eq]=large`
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await productRepository.find({where: {size: 'large'}});
+await productRepository.find({where: {size: {eq: 'large'}}}); // full condition syntax
+```
+
+### gt and lt
+
+```ts
+ONE_MONTH = 30 * 24 * 60 * 60 * 1000; // Month in milliseconds
+await transactionRepository.find({
+  where: {
+    userId: user.id,
+    time: {gt: Date.now() - ONE_MONTH},
+  },
+});
+```
+
+For example, the following query returns all instances of the order using
+a *where* filter that specifies a date property after (greater than) the
+specified date:
+
+{% include code-caption.html content="REST" %}
+
+`/orders?filter[where][date][gt]=2014-04-01T18:30:00.000Z`
+
+Or stringified JSON format:
+
+`/orders?filter={"where":{"date":{"gt":"2014-04-01T18:30:00.000Z"}}}`
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+orderRepository.find({
+  where: {
+    date: {gt: new Date('2014-04-01T18:30:00.000Z')},
+  },
+});
+```
+
+{% include code-caption.html content="REST" %}
+
+The top three weapons with a range over 900 meters:
+
+`/weapons?filter[where][effectiveRange][gt]=900&filter[limit]=3`
+
+Weapons with audibleRange less than 10:
+
+`/weapons?filter[where][audibleRange][lt]=10`
+
+### and / or
+
+The following code is an example of using the **"and"** operator to find reviews
+where the title is "My Post" and content is "Hello".
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await reviewRepository.find({
+  where: {and: [{title: 'My Post'}, {content: 'Hello'}]},
+});
+```
+
+{% include code-caption.html content="REST" %}
+
+`/reviews?filter[where][and][0][title]=My%20Post&filter[where][and][1][content]=Hello`
+
+Example using the **"or"** operator to finds reviews that either have title of
+"My Review" or content of "Hello".
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await reviewRepository.find({
+  where: {or: [{title: 'My Review'}, {content: 'Hello'}]},
+});
+```
+
+More complex example. The following
+expresses `(field1= foo and field2=bar) OR field1=morefoo`:
+
+```ts
+{
+  or: [{and: [{field1: 'foo'}, {field2: 'bar'}]}, {field1: 'morefoo'}];
+}
+```
+
+### between
+
+Example of between operator:
+
+{% include code-caption.html content="REST" %}
+
+`/shirts?filter[where][price][between][0]=0&filter[where][price][between][1]=7`
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await shirtRepository.find({where: {size: {between: [0, 7]}}});
+```
+
+### near
+
+The `where.<field>.near` filter is different from other where filters: most
+where filters **limit**the number of records returned, whereas `near` **orders**
+them, making it more like a SQL `order by` clause. By combining it with
+[`limit`](Limit-filter.html), you can create a query to get, for example, the
+**three records nearest to a given location**.
+
+For example:
+
+{% include code-caption.html content="REST" %}
+
+`/hotels?filter[where][geo][near]=153.536,-28.1&filter[limit]=3`
+
+GeoPoints can be expressed in any of the following ways:
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+location = new GeoPoint({lat: 42.266271, lng: -72.6700016}); // GeoPoint
+location = '42.266271,-72.6700016'; // String
+location = [42.266271, -72.6700016]; // Array
+location = {lat: 42.266271, lng: -72.6700016}; // Object Literal
+
+await hotelRepository.find({where: {geo: {near: location}}});
+```
+
+### near (ordering _and limiting by distance_)
+
+The near filter can take two additional properties:
+
+- `maxDistance`
+- `unit`
+
+When `maxDistance` is included in the filter, near behaves more like a typical
+where filter, limiting results to those within a given distance to a location.
+By default, `maxDistance` measures distance in **miles**.
+
+Example of finding the all hotels within two miles of a given GeoPoint:
+
+```ts
+const userLocation = new GeoPoint({
+  lat: 42.266271,
+  lng: -72.6700016,
+});
+const results = await hotelRepository.find({
+  where: {
+    location: {
+      near: userLocation,
+      maxDistance: 2,
+    },
+  },
+});
+```
+
+To change the units of measurement, specify `unit` property to one of the
+following:
+
+- `kilometers`
+- `meters`
+- `miles`
+- `feet`
+- `radians`
+- `degrees`
+
+For example, to change the query above to use kilometers instead of miles:
+
+```ts
+await hotelRepository.find({
+  where: {
+    location: {
+      near: userLocation,
+      maxDistance: 2,
+      unit: 'kilometers',
+    },
+  },
+});
+```
+
+{% include warning.html content="Spell Carefully!
+
+If `unit` value is mistyped, for example `'mile'` instead of `'miles'`, LoopBack
+will silently ignore the filter! " %}
+
+### like and nlike
+
+The like and nlike (not like) operators enable you to match SQL regular
+expressions. The regular expression format depends on the backend data source.
+
+Example of like operator:
+
+```ts
+await postRepository.find({where: {title: {like: 'M.-st'}}};
+```
+
+Example of nlike operator:
+
+```ts
+await postRepository.find({where: {title: {nlike: 'M.-XY'}}});
+```
+
+When using the memory connector:
+
+```ts
+await userRepository.find({where: {name: {like: '%St%'}}});
+await userRepository.find({where: {name: {nlike: 'M%XY'}}});
+```
+
+### like and nlike insensitive
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+const pattern = new RegExp(
+  '.*' + query + '.*',
+  'i',
+); /* case-insensitive RegExp search */
+await postRepository.find({where: {title: {like: pattern}}});
+```
+
+{% include code-caption.html content="REST" %}
+
+Stringified JSON format:
+
+`?filter={"where":{"title":{"like":"someth.*","options":"i"}}}`
+
+### ilike and nilike
+
+The ilike and nilike (not ilike) operators enable you to match case insensitive
+regular expressions. It is supported by the memory connector and Postgresql
+connectors.
+
+Example of ilike operator:
+
+```ts
+await postRepository.find({where: {title: {ilike: 'm.-st'}}});
+```
+
+Example of nilike operator:
+
+```ts
+await postRepository.find({where: {title: {nilike: 'm.-xy'}}});
+```
+
+When using the memory connector:
+
+```ts
+await userRepository.find({where: {name: {ilike: '%st%'}}});
+await userRepository.find({where: {name: {nilike: 's%xy'}}});
+```
+
+When using the
+[PostgreSQL connector](https://loopback.io/doc/en/lb4/PostgreSQL-connector.html):
+
+```ts
+await userRepository.find({where: {name: {ilike: 'john%'}}});
+```
+
+### inq
+
+The inq operator checks whether the value of the specified property matches any
+of the values provided in an array. The general syntax is:
+
+```ts
+{where: { property: { inq: [val1, val2, ...]}}}
+```
+
+Where:
+
+- *property* is the name of a property (field) in the model being queried.
+- _val1, val2_, and so on, are literal values in an array.
+
+Example of inq operator:
+
+{% include code-caption.html content="Node.js API" %}
+
+```ts
+await postRepository.find({where: {id: {inq: [123, 234]}}});
+```
+
+{% include code-caption.html content="REST" %}
+
+`/medias?filter[where][keywords][inq]=foo&filter[where][keywords][inq]=bar`
+
+Or stringified JSON format:
+
+`?filter={"where": {"keywords": {"inq": ["foo", "bar"]}}}`
+
+## WhereBuilder
+
+You can use the
+[`WhereBuilder`](https://loopback.io/doc/en/lb4/apidocs.repository.wherebuilder.html)
+to build and/or combine `where` clauses. You can build `where` clause with
+operators such as `and/or`, `gt`, etc.
+
+For example,
+
+```ts
+import WhereBuilder from '@loopback/repository';
+...
+const whereBuilder = new WhereBuilder();
+const where = whereBuilder
+  .between('price', 99, 299)
+  .and({brand: 'LoopBack'}, {discount: {lt: 20}})
+  .or({instock: true})
+  .build();
+```
+
+the filter will be built as
+
+```ts
+{
+  price: {between: [99, 299]},
+  and: [
+    {and: [{brand: 'LoopBack'}, {discount: {lt: 20}]},
+  ],
+  or: [
+    {instock: true},
+  ]
+}
+```
+
+Another common usage is to combine `where` clauses with
+[`WhereBuilder.impose`](https://loopback.io/doc/en/lb4/apidocs.repository.wherebuilder.impose.html).
+It adds a `where` object to the existing `where` filter by using the `and`
+operator. For example,
+
+```ts
+import WhereBuilder from '@loopback/repository';
+...
+const builder = new WhereBuilder<AnyObject>({brand: 'Toyota'});
+const where = builder.impose({model: 'Prius', instock: true}).build();
+```
+
+the filter will be built as
+
+```ts
+{
+  and: [
+  { brand: 'Toyota' }, { model: 'Prius', instock: true }
+  ],
+}
+```