Update docs for v8 (#1572)

This commit is contained in:
Tomas Della Vedova
2022-02-11 10:23:07 +01:00
committed by GitHub
parent a0c5c98a99
commit 759138c375
37 changed files with 315 additions and 1264 deletions

View File

@ -45,6 +45,7 @@ of `^7.10.0`).
| --------------- |------------------| ---------------------- | | --------------- |------------------| ---------------------- |
| `8.x` | `December 2019` | `7.11` (early 2021) | | `8.x` | `December 2019` | `7.11` (early 2021) |
| `10.x` | `April 2021` | `7.12` (mid 2021) | | `10.x` | `April 2021` | `7.12` (mid 2021) |
| `12.x` | `April 2022` | `8.2` (early 2022) |
### Compatibility ### Compatibility
@ -53,7 +54,7 @@ Elasticsearch language clients are only backwards compatible with default distri
| Elasticsearch Version | Client Version | | Elasticsearch Version | Client Version |
| --------------------- |----------------| | --------------------- |----------------|
| `main` | `main` | | `8.x` | `8.x` |
| `7.x` | `7.x` | | `7.x` | `7.x` |
| `6.x` | `6.x` | | `6.x` | `6.x` |
| `5.x` | `5.x` | | `5.x` | `5.x` |
@ -74,11 +75,9 @@ We recommend that you write a lightweight proxy that uses this client instead, y
- [Usage](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#client-usage) - [Usage](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#client-usage)
- [Client configuration](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html) - [Client configuration](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html)
- [API reference](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html) - [API reference](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html)
- [Breaking changes coming from the old client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/breaking-changes.html)
- [Authentication](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#authentication) - [Authentication](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#authentication)
- [Observability](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/observability.html) - [Observability](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/observability.html)
- [Creating a child client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/child.html) - [Creating a child client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/child.html)
- [Extend the client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/extend.html)
- [Client helpers](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-helpers.html) - [Client helpers](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-helpers.html)
- [Typescript support](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/typescript.html) - [Typescript support](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/typescript.html)
- [Testing](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-testing.html) - [Testing](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-testing.html)
@ -86,48 +85,6 @@ We recommend that you write a lightweight proxy that uses this client instead, y
## Quick start ## Quick start
First of all, require the client and initialize it:
```js
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
```
You can use both the callback-style API and the promise-style API, both behave the same way.
```js
// promise API
const result = await client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
})
// callback API
client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
}, (err, result) => {
if (err) console.log(err)
})
```
The returned value of **every** API call is formed as follows:
```ts
{
body: object | boolean
statusCode: number
headers: object
warnings: [string]
meta: object
}
```
Let's see a complete example!
```js ```js
'use strict' 'use strict'
@ -138,8 +95,7 @@ async function run () {
// Let's start by indexing some data // Let's start by indexing some data
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 document: {
body: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.' quote: 'Winter is coming.'
} }
@ -147,8 +103,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 document: {
body: {
character: 'Daenerys Targaryen', character: 'Daenerys Targaryen',
quote: 'I am the blood of the dragon.' quote: 'I am the blood of the dragon.'
} }
@ -156,8 +111,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 document: {
body: {
character: 'Tyrion Lannister', character: 'Tyrion Lannister',
quote: 'A mind needs books like a sword needs a whetstone.' quote: 'A mind needs books like a sword needs a whetstone.'
} }
@ -168,17 +122,14 @@ async function run () {
await client.indices.refresh({ index: 'game-of-thrones' }) await client.indices.refresh({ index: 'game-of-thrones' })
// Let's search! // Let's search!
const { body } = await client.search({ const result= await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 query: {
body: { match: { quote: 'winter' }
query: {
match: { quote: 'winter' }
}
} }
}) })
console.log(body.hits.hits) console.log(result.hits.hits)
} }
run().catch(console.log) run().catch(console.log)
@ -211,13 +162,13 @@ const { Client: Client7 } = require('es7')
const client6 = new Client6({ node: 'http://localhost:9200' }) const client6 = new Client6({ node: 'http://localhost:9200' })
const client7 = new Client7({ node: 'http://localhost:9201' }) const client7 = new Client7({ node: 'http://localhost:9201' })
client6.info(console.log) client6.info().then(console.log, console.log)
client7.info(console.log) client7.info().then(console.log, console.log)
``` ```
Finally, if you want to install the client for the next version of Elasticsearch *(the one that lives in Elasticsearchs master branch)*, you can use the following command: Finally, if you want to install the client for the next version of Elasticsearch *(the one that lives in Elasticsearchs main branch)*, you can use the following command:
```sh ```sh
npm install esmaster@github:elastic/elasticsearch-js npm install esmain@github:elastic/elasticsearch-js
``` ```
## License ## License

View File

@ -45,9 +45,9 @@ is performed here, this means that if you want to swap the default HTTP client
[source,js] [source,js]
---- ----
const { Client, Connection } = require('@elastic/elasticsearch') const { Client, BaseConnection } = require('@elastic/elasticsearch')
class MyConnection extends Connection { class MyConnection extends BaseConnection {
request (params, callback) { request (params, callback) {
// your code // your code
} }

View File

@ -32,7 +32,7 @@ Or it can be an object (or an array of objects) that represents the node:
---- ----
node: { node: {
url: new URL('http://localhost:9200'), url: new URL('http://localhost:9200'),
ssl: 'ssl options', tls: 'tls options',
agent: 'http agent options', agent: 'http agent options',
id: 'custom node id', id: 'custom node id',
headers: { 'custom': 'headers' } headers: { 'custom': 'headers' }
@ -118,8 +118,8 @@ _Default:_ `false`
_Options:_ `'gzip'`, `false` + _Options:_ `'gzip'`, `false` +
_Default:_ `false` _Default:_ `false`
|`ssl` |`tls`
|`http.SecureContextOptions` - ssl https://nodejs.org/api/tls.html[configuraton]. + |`http.SecureContextOptions` - tls https://nodejs.org/api/tls.html[configuraton]. +
_Default:_ `null` _Default:_ `null`
|`proxy` |`proxy`
@ -267,24 +267,4 @@ _Default:_ `null`
|`number` - When configured, it verifies that the compressed response size is lower than the configured number, if it's higher it will abort the request. It cannot be higher than buffer.constants.MAX_LENTGH + |`number` - When configured, it verifies that the compressed response size is lower than the configured number, if it's higher it will abort the request. It cannot be higher than buffer.constants.MAX_LENTGH +
_Default:_ `null` _Default:_ `null`
|=== |===
[discrete]
==== Performances considerations
By default, the client will protection you against prototype poisoning attacks.
Read https://web.archive.org/web/20200319091159/https://hueniverse.com/square-brackets-are-the-enemy-ff5b9fd8a3e8?gi=184a27ee2a08[this article] to learn more.
If needed you can disable prototype poisoning protection entirely or one of the two checks.
Read the `secure-json-parse` https://github.com/fastify/secure-json-parse[documentation] to learn more.
While it's good to be safe, you should know that security always comes with a cost.
With big enough payloads, this security check could causea drop in the overall performances,
which might be a problem for your application.
If you know you can trust the data stored in Elasticsearch, you can safely disable this check.
[source,js]
----
const client = new Client({
disablePrototypePoisoningProtection: true
})
----

View File

@ -1,334 +0,0 @@
[[breaking-changes]]
=== Breaking changes coming from the old client
If you were already using the previous version of this client the one you used
to install with `npm install elasticsearch` you will encounter some breaking
changes.
[discrete]
==== Dont panic!
Every breaking change was carefully weighed, and each is justified. Furthermore,
the new codebase has been rewritten with modern JavaScript and has been
carefully designed to be easy to maintain.
[discrete]
==== Breaking changes
* Minimum supported version of Node.js is `v8`.
* Everything has been rewritten using ES6 classes to help users extend the
defaults more easily.
* There is no longer an integrated logger. The client now is an event emitter
that emits the following events: `request`, `response`, and `error`.
* The code is no longer shipped with all the versions of the API, but only that
of the packages major version. This means that if you are using {es} `v6`, you
are required to install `@elastic/elasticsearch@6`, and so on.
* The internals are completely different, so if you used to tweak them a lot,
you will need to refactor your code. The public API should be almost the same.
* There is no longer browser support, for that will be distributed via another
module: `@elastic/elasticsearch-browser`. This module is intended for Node.js
only.
* The returned value of an API call will no longer be the `body`, `statusCode`,
and `headers` for callbacks, and only the `body` for promises. The new returned
value will be a unique object containing the `body`, `statusCode`, `headers`,
`warnings`, and `meta`, for both callback and promises.
[source,js]
----
// before
const body = await client.search({
index: 'my-index',
body: { foo: 'bar' }
})
client.search({
index: 'my-index',
body: { foo: 'bar' }
}, (err, body, statusCode, headers) => {
if (err) console.log(err)
})
// after
const { body, statusCode, headers, warnings } = await client.search({
index: 'my-index',
body: { foo: 'bar' }
})
client.search({
index: 'my-index',
body: { foo: 'bar' }
}, (err, { body, statusCode, headers, warnings }) => {
if (err) console.log(err)
})
----
* Errors: there is no longer a custom error class for every HTTP status code
(such as `BadRequest` or `NotFound`). There is instead a single `ResponseError`.
Every error class has been renamed, and now each is suffixed with `Error` at the
end.
* Removed errors: `RequestTypeError`, `Generic`, and all the status code
specific errors (such as `BadRequest` or `NotFound`).
* Added errors: `ConfigurationError` (in case of bad configurations) and
`ResponseError` that contains all the data you may need to handle the specific
error, such as `statusCode`, `headers`, `body`, and `message`.
* Renamed errors:
** `RequestTimeout` (408 statusCode) => `TimeoutError`
** `ConnectionFault` => `ConnectionError`
** `NoConnections` => `NoLivingConnectionsError`
** `Serialization` => `SerializationError`
** `Serialization` => `DeserializationError`
* You must specify the port number in the configuration. In the previous
version, you can specify the host and port in a variety of ways. With the new
client, there is only one way to do it, via the `node` parameter.
* Certificates are verified by default, if you want to disable certificates verification, you should set the `rejectUnauthorized` option to `false` inside the `ssl` configuration:
[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({
ssl: { rejectUnauthorized: false }
})
----
* The `plugins` option has been removed. If you want to extend the client now,
you should use the `client.extend` API.
[source,js]
----
// before
const { Client } = require('elasticsearch')
const client = new Client({ plugins: [...] })
// after
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ ... })
client.extend(...)
----
* There is a clear distinction between the API related parameters and the client
related configurations. The parameters `ignore`, `headers`, `requestTimeout` and
`maxRetries` are no longer part of the API object and you need to specify them
in a second option object.
[source,js]
----
// before
const body = await client.search({
index: 'my-index',
body: { foo: 'bar' },
ignore: [404]
})
client.search({
index: 'my-index',
body: { foo: 'bar' },
ignore: [404]
}, (err, body, statusCode, headers) => {
if (err) console.log(err)
})
// after
const { body, statusCode, headers, warnings } = await client.search({
index: 'my-index',
body: { foo: 'bar' }
}, {
ignore: [404]
})
client.search({
index: 'my-index',
body: { foo: 'bar' }
}, {
ignore: [404]
}, (err, { body, statusCode, headers, warnings }) => {
if (err) console.log(err)
})
----
* The `transport.request` method no longer accepts the `query` key. Use the
`querystring` key instead (which can be a string or an object). You also
need to send a bulk-like request instead of the `body` key, use the `bulkBody`
key. In this method, the client specific parameters should be passed as a second
object.
[source,js]
----
// before
const body = await client.transport.request({
method: 'GET',
path: '/my-index/_search',
body: { foo: 'bar' },
query: { bar: 'baz' }
ignore: [404]
})
client.transport.request({
method: 'GET',
path: '/my-index/_search',
body: { foo: 'bar' },
query: { bar: 'baz' }
ignore: [404]
}, (err, body, statusCode, headers) => {
if (err) console.log(err)
})
// after
const { body, statusCode, headers, warnings } = await client.transport.request({
method: 'GET',
path: '/my-index/_search',
body: { foo: 'bar' },
querystring: { bar: 'baz' }
}, {
ignore: [404]
})
client.transport.request({
method: 'GET',
path: '/my-index/_search',
body: { foo: 'bar' },
querystring: { bar: 'baz' }
}, {
ignore: [404]
}, (err, { body, statusCode, headers, warnings }) => {
if (err) console.log(err)
})
----
[discrete]
==== Talk is cheap. Show me the code.
You can find a code snippet with the old client below followed by the same code
logic but with the new client.
[source,js]
----
const { Client, errors } = require('elasticsearch')
const client = new Client({
host: 'http://localhost:9200',
plugins: [utility]
})
async function run () {
try {
const body = await client.search({
index: 'game-of-thrones',
body: {
query: {
match: { quote: 'winter' }
}
}
ignore: [404]
})
console.log(body)
} catch (err) {
if (err instanceof errors.BadRequest) {
console.log('Bad request')
} else {
console.log(err)
}
}
}
function utility (Client, config, components) {
const ca = components.clientAction.factory
Client.prototype.utility = components.clientAction.namespaceFactory()
const utility = Client.prototype.utility.prototype
utility.index = ca({
params: {
refresh: {
type: 'enum',
options: [
'true',
'false',
'wait_for',
''
]
},
},
urls: [
{
fmt: '/<%=index%>/_doc',
req: {
index: {
type: 'string',
required: true
}
}
}
],
needBody: true,
method: 'POST'
})
})
----
And now with the new client.
[source,js]
----
const { Client, errors } = require('@elastic/elasticsearch')
// NOTE: `host` has been renamed to `node`,
// and `plugins` is no longer supported
const client = new Client({ node: 'http://localhost:9200' })
async function run () {
try {
// NOTE: we are using the destructuring assignment
const { body } = await client.search({
index: 'game-of-thrones',
body: {
query: {
match: { quote: 'winter' }
}
}
// NOTE: `ignore` now is in a separated object
}, {
ignore: [404]
})
console.log(body)
} catch (err) {
// NOTE: we are checking the `statusCode` property
if (err.statusCode === 400) {
console.log('Bad request')
} else {
console.log(err)
}
}
}
// NOTE: we can still extend the client, but with a different API.
// This new API is a little bit more verbose, since you must write
// your own validations, but it's way more flexible.
client.extend('utility.index', ({ makeRequest, ConfigurationError }) => {
return function utilityIndex (params, options) {
const { body, index, ...querystring } = params
if (body == null) throw new ConfigurationError('Missing body')
if (index == null) throw new ConfigurationError('Missing index')
const requestParams = {
method: 'POST',
path: `/${index}/_doc`,
body: body,
querystring
}
return makeRequest(requestParams, options)
}
})
----

View File

@ -28,6 +28,6 @@ const child = client.child({
requestTimeout: 1000 requestTimeout: 1000
}) })
client.info(console.log) client.info().then(console.log, console.log)
child.info(console.log) child.info().then(console.log, console.log)
---- ----

View File

@ -8,5 +8,4 @@ section, you can see the possible options that you can use to configure it.
* <<basic-config>> * <<basic-config>>
* <<advanced-config>> * <<advanced-config>>
* <<child>> * <<child>>
* <<extend>>
* <<client-testing>> * <<client-testing>>

View File

@ -32,7 +32,7 @@ the `auth` option.
NOTE: When connecting to Elastic Cloud, the client will automatically enable NOTE: When connecting to Elastic Cloud, the client will automatically enable
both request and response compression by default, since it yields significant both request and response compression by default, since it yields significant
throughput improvements. Moreover, the client will also set the ssl option throughput improvements. Moreover, the client will also set the tls option
`secureProtocol` to `TLSv1_2_method` unless specified otherwise. You can still `secureProtocol` to `TLSv1_2_method` unless specified otherwise. You can still
override this option by configuring them. override this option by configuring them.
@ -151,13 +151,13 @@ const client = new Client({
[discrete] [discrete]
[[auth-ssl]] [[auth-tls]]
==== SSL configuration ==== TLS configuration
Without any additional configuration you can specify `https://` node urls, and Without any additional configuration you can specify `https://` node urls, and
the certificates used to sign these requests will be verified. To turn off the certificates used to sign these requests will be verified. To turn off
certificate verification, you must specify an `ssl` object in the top level certificate verification, you must specify an `tls` object in the top level
config and set `rejectUnauthorized: false`. The default `ssl` values are the config and set `rejectUnauthorized: false`. The default `tls` values are the
same that Node.js's https://nodejs.org/api/tls.html#tls_tls_connect_options_callback[`tls.connect()`] same that Node.js's https://nodejs.org/api/tls.html#tls_tls_connect_options_callback[`tls.connect()`]
uses. uses.
@ -170,7 +170,7 @@ const client = new Client({
username: 'elastic', username: 'elastic',
password: 'changeme' password: 'changeme'
}, },
ssl: { tls: {
ca: fs.readFileSync('./cacert.pem'), ca: fs.readFileSync('./cacert.pem'),
rejectUnauthorized: false rejectUnauthorized: false
} }
@ -193,7 +193,7 @@ const client = new Client({
auth: { ... }, auth: { ... },
// the fingerprint (SHA256) of the CA certificate that is used to sign the certificate that the Elasticsearch node presents for TLS. // the fingerprint (SHA256) of the CA certificate that is used to sign the certificate that the Elasticsearch node presents for TLS.
caFingerprint: '20:0D:CA:FA:76:...', caFingerprint: '20:0D:CA:FA:76:...',
ssl: { tls: {
// might be required if it's a self-signed certificate // might be required if it's a self-signed certificate
rejectUnauthorized: false rejectUnauthorized: false
} }
@ -214,31 +214,32 @@ and every method exposes the same signature.
const { Client } = require('@elastic/elasticsearch') const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
// promise API
const result = await client.search({ const result = await client.search({
index: 'my-index', index: 'my-index',
body: { query: {
query: { match: { hello: 'world' }
match: { hello: 'world' }
}
} }
}) })
// callback API
client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
}, (err, result) => {
if (err) console.log(err)
})
---- ----
The returned value of every API call is designed as follows: The returned value of every API call is the response body from {es}.
If you need to access additonal metadata, such as the status code or headers,
you must specify `meta: true` in the request options:
[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
const result = await client.search({
index: 'my-index',
query: {
match: { hello: 'world' }
}
}, { meta: true })
----
In this case, the result will be:
[source,ts] [source,ts]
---- ----
{ {
@ -252,44 +253,10 @@ The returned value of every API call is designed as follows:
NOTE: The body is a boolean value when you use `HEAD` APIs. NOTE: The body is a boolean value when you use `HEAD` APIs.
The above value is returned even if there is an error during the execution of
the request, this means that you can safely use the
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment[destructuring assignment].
The `meta` key contains all the information about the request, such as attempt,
options, and the connection that has been used.
[source,js]
----
// promise API
const { body } = await client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
})
// callback API
client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
}, (err, { body }) => {
if (err) console.log(err)
})
----
[discrete] [discrete]
==== Aborting a request ==== Aborting a request
If needed, you can abort a running request by calling the `request.abort()` If needed, you can abort a running request by using the `AbortController` standard.
method returned by the API.
CAUTION: If you abort a request, the request will fail with a CAUTION: If you abort a request, the request will fail with a
`RequestAbortedError`. `RequestAbortedError`.
@ -297,51 +264,21 @@ CAUTION: If you abort a request, the request will fail with a
[source,js] [source,js]
---- ----
const request = client.search({ const AbortController = require('node-abort-controller')
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
const abortController = new AbortController()
setImmediate(() => abortController.abort())
const result = await client.search({
index: 'my-index', index: 'my-index',
body: { query: {
query: { match: { hello: 'world' }
match: { hello: 'world' }
}
} }
}, { }, { signal: abortController.signal })
ignore: [404],
maxRetries: 3
}, (err, result) => {
if (err) {
console.log(err) // RequestAbortedError
} else {
console.log(result)
}
})
request.abort()
---- ----
The same behavior is valid for the promise style API as well.
[source,js]
----
const request = client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
}, {
ignore: [404],
maxRetries: 3
})
request
.then(result => console.log(result))
.catch(err => console.log(err)) // RequestAbortedError
request.abort()
----
[discrete] [discrete]
==== Request specific options ==== Request specific options
@ -349,7 +286,6 @@ If needed you can pass request specific options in a second object:
[source,js] [source,js]
---- ----
// promise API
const result = await client.search({ const result = await client.search({
index: 'my-index', index: 'my-index',
body: { body: {
@ -361,21 +297,6 @@ const result = await client.search({
ignore: [404], ignore: [404],
maxRetries: 3 maxRetries: 3
}) })
// callback API
client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
}, {
ignore: [404],
maxRetries: 3
}, (err, { body }) => {
if (err) console.log(err)
})
---- ----
@ -427,6 +348,10 @@ _Default:_ `null`
|`number` - When configured, it verifies that the compressed response size is lower than the configured number, if it's higher it will abort the request. It cannot be higher than buffer.constants.MAX_LENTGH + |`number` - When configured, it verifies that the compressed response size is lower than the configured number, if it's higher it will abort the request. It cannot be higher than buffer.constants.MAX_LENTGH +
_Default:_ `null` _Default:_ `null`
|`signal`
|`AbortSignal` - The AbortSignal instance to allow request abortion. +
_Default:_ `null`
|=== |===
[discrete] [discrete]

View File

@ -12,9 +12,9 @@ const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
const { body: bulkResponse } = await client.bulk({ const bulkResponse = await client.bulk({
refresh: true, refresh: true,
body: [ operations: [
// operation to perform // operation to perform
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
// the document to index // the document to index
@ -43,13 +43,11 @@ async function run () {
} }
// Let's search! // Let's search!
const { body } = await client.search({ const result = await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { query: {
query: { match: {
match: { quote: 'winter'
quote: 'winter'
}
} }
} }
}, { }, {
@ -59,17 +57,17 @@ async function run () {
// stream async iteration, available in Node.js ≥ 10 // stream async iteration, available in Node.js ≥ 10
let payload = '' let payload = ''
body.setEncoding('utf8') body.setEncoding('utf8')
for await (const chunk of body) { for await (const chunk of result) {
payload += chunk payload += chunk
} }
console.log(JSON.parse(payload)) console.log(JSON.parse(payload))
// classic stream callback style // classic stream callback style
let payload = '' let payload = ''
body.setEncoding('utf8') result.setEncoding('utf8')
body.on('data', chunk => { payload += chunk }) result.on('data', chunk => { payload += chunk })
body.on('error', console.log) result.on('error', console.log)
body.on('end', () => { result.on('end', () => {
console.log(JSON.parse(payload)) console.log(JSON.parse(payload))
}) })
} }
@ -91,9 +89,10 @@ const fastify = require('fastify')()
fastify.post('/search/:index', async (req, reply) => { fastify.post('/search/:index', async (req, reply) => {
const { body, statusCode, headers } = await client.search({ const { body, statusCode, headers } = await client.search({
index: req.params.index, index: req.params.index,
body: req.body ...req.body
}, { }, {
asStream: true asStream: true,
meta: true
}) })
reply.code(statusCode).headers(headers) reply.code(statusCode).headers(headers)

View File

@ -19,7 +19,7 @@ const client = new Client({
async function run () { async function run () {
await client.indices.create({ await client.indices.create({
index: 'tweets', index: 'tweets',
body: { operations: {
mappings: { mappings: {
properties: { properties: {
id: { type: 'integer' }, id: { type: 'integer' },
@ -58,9 +58,9 @@ async function run () {
date: new Date() date: new Date()
}] }]
const body = dataset.flatMap(doc => [{ index: { _index: 'tweets' } }, doc]) const operations = dataset.flatMap(doc => [{ index: { _index: 'tweets' } }, doc])
const { body: bulkResponse } = await client.bulk({ refresh: true, body }) const bulkResponse = await client.bulk({ refresh: true, operations })
if (bulkResponse.errors) { if (bulkResponse.errors) {
const erroredDocuments = [] const erroredDocuments = []
@ -84,7 +84,7 @@ async function run () {
console.log(erroredDocuments) console.log(erroredDocuments)
} }
const { body: count } = await client.count({ index: 'tweets' }) const count = await client.count({ index: 'tweets' })
console.log(count) console.log(count)
} }

View File

@ -16,18 +16,18 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1', id: '1',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.' quote: 'Winter is coming.'
} }
}) })
const { body } = await client.exists({ const exists = await client.exists({
index: 'game-of-thrones', index: 'game-of-thrones',
id: 1 id: 1
}) })
console.log(body) // true console.log(exists) // true
} }
run().catch(console.log) run().catch(console.log)

View File

@ -16,18 +16,18 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1', id: '1',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.' quote: 'Winter is coming.'
} }
}) })
const { body } = await client.get({ const document = await client.get({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1' id: '1'
}) })
console.log(body) console.log(document)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -11,9 +11,9 @@ const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
const { body: bulkResponse } = await client.bulk({ const bulkResponse = await client.bulk({
refresh: true, refresh: true,
body: [ operations: [
// operation to perform // operation to perform
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
// the document to index // the document to index
@ -42,7 +42,7 @@ async function run () {
} }
// Let's search! // Let's search!
const { body } = await client.search({ const result = await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { body: {
query: { query: {
@ -55,7 +55,7 @@ async function run () {
ignore: [404] ignore: [404]
}) })
console.log(body) // ResponseError console.log(result) // ResponseError
} }
run().catch(console.log) run().catch(console.log)

View File

@ -17,7 +17,6 @@ Following you can find some examples on how to use the client.
* Executing a <<search_examples,search>> request; * Executing a <<search_examples,search>> request;
* I need <<suggest_examples,suggestions>>; * I need <<suggest_examples,suggestions>>;
* How to use the <<transport_request_examples,transport.request>> method; * How to use the <<transport_request_examples,transport.request>> method;
* How to use <<typescript_examples,TypeScript>>;
include::asStream.asciidoc[] include::asStream.asciidoc[]
include::bulk.asciidoc[] include::bulk.asciidoc[]
@ -29,7 +28,6 @@ include::scroll.asciidoc[]
include::search.asciidoc[] include::search.asciidoc[]
include::suggest.asciidoc[] include::suggest.asciidoc[]
include::transport.request.asciidoc[] include::transport.request.asciidoc[]
include::typescript.asciidoc[]
include::sql.query.asciidoc[] include::sql.query.asciidoc[]
include::update.asciidoc[] include::update.asciidoc[]
include::update_by_query.asciidoc[] include::update_by_query.asciidoc[]

View File

@ -12,9 +12,9 @@ const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
const { body: bulkResponse } = await client.bulk({ const bulkResponse = await client.bulk({
refresh: true, refresh: true,
body: [ operations: [
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
{ {
character: 'Ned Stark', character: 'Ned Stark',
@ -40,8 +40,8 @@ async function run () {
process.exit(1) process.exit(1)
} }
const { body } = await client.msearch({ const result = await client.msearch({
body: [ searches: [
{ index: 'game-of-thrones' }, { index: 'game-of-thrones' },
{ query: { match: { character: 'Daenerys' } } }, { query: { match: { character: 'Daenerys' } } },
@ -50,7 +50,7 @@ async function run () {
] ]
}) })
console.log(body.responses) console.log(result.responses)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -70,17 +70,15 @@ module.exports = async (req, res) => {
// expose you to the risk that a malicious user // expose you to the risk that a malicious user
// could overload your cluster by crafting // could overload your cluster by crafting
// expensive queries. // expensive queries.
body: { _source: ['id', 'url', 'name'], // the fields you want to show in the autocompletion
_source: ['id', 'url', 'name'], // the fields you want to show in the autocompletion size: 0,
size: 0, // https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
// https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html suggest: {
suggest: { suggestions: {
suggestions: { prefix: req.query.q,
prefix: req.query.q, completion: {
completion: { field: 'suggest',
field: 'suggest', size: 5
size: 5
}
} }
} }
} }
@ -93,7 +91,7 @@ module.exports = async (req, res) => {
// It might be useful to configure http control caching headers // It might be useful to configure http control caching headers
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
// res.setHeader('stale-while-revalidate', '30') // res.setHeader('stale-while-revalidate', '30')
res.json(response.body) res.json(response)
} catch (err) { } catch (err) {
res.status(err.statusCode || 500) res.status(err.statusCode || 500)
res.json({ res.json({

View File

@ -62,7 +62,7 @@ module.exports = async (req, res) => {
} }
}) })
res.json(response.body) res.json(response)
} catch (err) { } catch (err) {
res.status(err.statusCode || 500) res.status(err.statusCode || 500)
res.json({ res.json({

View File

@ -56,11 +56,12 @@ module.exports = async (req, res) => {
const response = await client.index({ const response = await client.index({
index: INDEX, index: INDEX,
id: req.query.id, id: req.query.id,
body: req.body document: req.body
}, { }, {
headers: { headers: {
Authorization: `ApiKey ${token}` Authorization: `ApiKey ${token}`
} },
meta: true
}) })
res.status(response.statusCode) res.status(response.statusCode)

View File

@ -60,10 +60,8 @@ module.exports = async (req, res) => {
// expose you to the risk that a malicious user // expose you to the risk that a malicious user
// could overload your cluster by crafting // could overload your cluster by crafting
// expensive queries. // expensive queries.
body: { query: {
query: { match: { field: req.body.text }
match: { field: req.body.text }
}
} }
}, { }, {
headers: { headers: {
@ -74,7 +72,7 @@ module.exports = async (req, res) => {
// It might be useful to configure http control caching headers // It might be useful to configure http control caching headers
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
// res.setHeader('stale-while-revalidate', '30') // res.setHeader('stale-while-revalidate', '30')
res.json(response.body) res.json(response)
} catch (err) { } catch (err) {
res.status(err.statusCode || 500) res.status(err.statusCode || 500)
res.json({ res.json({

View File

@ -11,7 +11,7 @@
"author": "Tomas Della Vedova", "author": "Tomas Della Vedova",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@elastic/elasticsearch": "^7.10.0" "@elastic/elasticsearch": "^8.0.0"
}, },
"devDependencies": { "devDependencies": {
"standard": "^16.0.3" "standard": "^16.0.3"

View File

@ -43,21 +43,19 @@ async function generateApiKeys (opts) {
} }
}) })
const { body } = await client.security.createApiKey({ const result = await client.security.createApiKey({
body: { name: 'elasticsearch-proxy',
name: 'elasticsearch-proxy', role_descriptors: {
role_descriptors: { 'elasticsearch-proxy-users': {
'elasticsearch-proxy-users': { index: [{
index: [{ names: indexNames,
names: indexNames, privileges
privileges }]
}]
}
} }
} }
}) })
return Buffer.from(`${body.id}:${body.api_key}`).toString('base64') return Buffer.from(`${result.id}:${result.api_key}`).toString('base64')
} }
generateApiKeys() generateApiKeys()

View File

@ -20,7 +20,7 @@ const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.', quote: 'Winter is coming.',
house: 'stark' house: 'stark'
@ -29,7 +29,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Arya Stark', character: 'Arya Stark',
quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.', quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.',
house: 'stark' house: 'stark'
@ -39,7 +39,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
refresh: true, refresh: true,
body: { document: {
character: 'Tyrion Lannister', character: 'Tyrion Lannister',
quote: 'A Lannister always pays his debts.', quote: 'A Lannister always pays his debts.',
house: 'lannister' house: 'lannister'
@ -47,33 +47,29 @@ async function run () {
}) })
await client.reindex({ await client.reindex({
waitForCompletion: true, wait_for_completion: true,
refresh: true, refresh: true,
body: { source: {
source: { index: 'game-of-thrones',
index: 'game-of-thrones', query: {
query: { match: { character: 'stark' }
match: { character: 'stark' }
}
},
dest: {
index: 'stark-index'
},
script: {
lang: 'painless',
source: 'ctx._source.remove("house")'
} }
},
dest: {
index: 'stark-index'
},
script: {
lang: 'painless',
source: 'ctx._source.remove("house")'
} }
}) })
const { body } = await client.search({ const result = await client.search({
index: 'stark-index', index: 'stark-index',
body: { query: { match_all: {} }
query: { match_all: {} }
}
}) })
console.log(body.hits.hits) console.log(result.hits.hits)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -33,12 +33,12 @@ async function run () {
const responseQueue = [] const responseQueue = []
// Let's index some data! // Let's index some data!
const { body: bulkResponse } = await client.bulk({ const bulkResponse = await client.bulk({
// here we are forcing an index refresh, // here we are forcing an index refresh,
// otherwise we will not get any result // otherwise we will not get any result
// in the consequent search // in the consequent search
refresh: true, refresh: true,
body: [ operations: [
// operation to perform // operation to perform
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
// the document to index // the document to index
@ -76,17 +76,15 @@ async function run () {
size: 1, size: 1,
// filter the source to only include the quote field // filter the source to only include the quote field
_source: ['quote'], _source: ['quote'],
body: { query: {
query: { match_all: {}
match_all: {}
}
} }
}) })
responseQueue.push(response) responseQueue.push(response)
while (responseQueue.length) { while (responseQueue.length) {
const { body } = responseQueue.shift() const body = responseQueue.shift()
// collect the titles from this response // collect the titles from this response
body.hits.hits.forEach(function (hit) { body.hits.hits.forEach(function (hit) {
@ -127,7 +125,7 @@ async function * scrollSearch (params) {
let response = await client.search(params) let response = await client.search(params)
while (true) { while (true) {
const sourceHits = response.body.hits.hits const sourceHits = response.hits.hits
if (sourceHits.length === 0) { if (sourceHits.length === 0) {
break break
@ -137,12 +135,12 @@ async function * scrollSearch (params) {
yield hit yield hit
} }
if (!response.body._scroll_id) { if (!response._scroll_id) {
break break
} }
response = await client.scroll({ response = await client.scroll({
scrollId: response.body._scroll_id, scrollId: response._scroll_id,
scroll: params.scroll scroll: params.scroll
}) })
} }
@ -151,7 +149,7 @@ async function * scrollSearch (params) {
async function run () { async function run () {
await client.bulk({ await client.bulk({
refresh: true, refresh: true,
body: [ operations: [
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
{ {
character: 'Ned Stark', character: 'Ned Stark',
@ -177,10 +175,8 @@ async function run () {
scroll: '30s', scroll: '30s',
size: 1, size: 1,
_source: ['quote'], _source: ['quote'],
body: { query: {
query: { match_all: {}
match_all: {}
}
} }
} }

View File

@ -18,7 +18,7 @@ async function run () {
// Let's start by indexing some data // Let's start by indexing some data
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.' quote: 'Winter is coming.'
} }
@ -26,7 +26,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Daenerys Targaryen', character: 'Daenerys Targaryen',
quote: 'I am the blood of the dragon.' quote: 'I am the blood of the dragon.'
} }
@ -38,25 +38,23 @@ async function run () {
// otherwise we will not get any result // otherwise we will not get any result
// in the consequent search // in the consequent search
refresh: true, refresh: true,
body: { document: {
character: 'Tyrion Lannister', character: 'Tyrion Lannister',
quote: 'A mind needs books like a sword needs a whetstone.' quote: 'A mind needs books like a sword needs a whetstone.'
} }
}) })
// Let's search! // Let's search!
const { body } = await client.search({ const result = await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { query: {
query: { match: {
match: { quote: 'winter'
quote: 'winter'
}
} }
} }
}) })
console.log(body.hits.hits) console.log(result.hits.hits)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -22,7 +22,7 @@ const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.', quote: 'Winter is coming.',
house: 'stark' house: 'stark'
@ -31,7 +31,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Arya Stark', character: 'Arya Stark',
quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.', quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.',
house: 'stark' house: 'stark'
@ -41,25 +41,23 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
refresh: true, refresh: true,
body: { document: {
character: 'Tyrion Lannister', character: 'Tyrion Lannister',
quote: 'A Lannister always pays his debts.', quote: 'A Lannister always pays his debts.',
house: 'lannister' house: 'lannister'
} }
}) })
const { body } = await client.sql.query({ const result = await client.sql.query({
body: { query: "SELECT * FROM \"game-of-thrones\" WHERE house='stark'"
query: "SELECT * FROM \"game-of-thrones\" WHERE house='stark'"
}
}) })
console.log(body) console.log(result)
const data = body.rows.map(row => { const data = result.rows.map(row => {
const obj = {} const obj = {}
for (let i = 0; i < row.length; i++) { for (let i = 0; i < row.length; i++) {
obj[body.columns[i].name] = row[i] obj[result.columns[i].name] = row[i]
} }
return obj return obj
}) })

View File

@ -15,9 +15,9 @@ const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
const { body: bulkResponse } = await client.bulk({ const bulkResponse = await client.bulk({
refresh: true, refresh: true,
body: [ operations: [
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
{ {
character: 'Ned Stark', character: 'Ned Stark',
@ -43,22 +43,20 @@ async function run () {
process.exit(1) process.exit(1)
} }
const { body } = await client.search({ const result = await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { query: {
query: { match: { quote: 'winter' }
match: { quote: 'witner' } },
}, suggest: {
suggest: { gotsuggest: {
gotsuggest: { text: 'winter',
text: 'witner', term: { field: 'quote' }
term: { field: 'quote' }
}
} }
} }
}) })
console.log(body) console.log(result)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -23,9 +23,9 @@ const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
const { body: bulkResponse } = await client.bulk({ const bulkResponse = await client.bulk({
refresh: true, refresh: true,
body: [ operations: [
{ index: { _index: 'game-of-thrones' } }, { index: { _index: 'game-of-thrones' } },
{ {
character: 'Ned Stark', character: 'Ned Stark',
@ -51,7 +51,7 @@ async function run () {
process.exit(1) process.exit(1)
} }
const { body } = await client.transport.request({ const response = await client.transport.request({
method: 'POST', method: 'POST',
path: '/game-of-thrones/_search', path: '/game-of-thrones/_search',
body: { body: {
@ -64,7 +64,7 @@ async function run () {
querystring: {} querystring: {}
}) })
console.log(body) console.log(response)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -1,72 +0,0 @@
[[typescript_examples]]
=== Typescript
The client offers a first-class support for TypeScript, since it ships the type
definitions for every exposed API.
NOTE: If you are using TypeScript you will be required to use _snake_case_ style
to define the API parameters instead of _camelCase_.
[source,ts]
----
'use strict'
import { Client, ApiResponse, RequestParams } from '@elastic/elasticsearch'
const client = new Client({ node: 'http://localhost:9200' })
async function run (): void {
// Let's start by indexing some data
const doc1: RequestParams.Index = {
index: 'game-of-thrones',
body: {
character: 'Ned Stark',
quote: 'Winter is coming.'
}
}
await client.index(doc1)
const doc2: RequestParams.Index = {
index: 'game-of-thrones',
body: {
character: 'Daenerys Targaryen',
quote: 'I am the blood of the dragon.'
}
}
await client.index(doc2)
const doc3: RequestParams.Index = {
index: 'game-of-thrones',
// here we are forcing an index refresh,
// otherwise we will not get any result
// in the consequent search
refresh: true,
body: {
character: 'Tyrion Lannister',
quote: 'A mind needs books like a sword needs a whetstone.'
}
}
await client.index(doc3)
// Let's search!
const params: RequestParams.Search = {
index: 'game-of-thrones',
body: {
query: {
match: {
quote: 'winter'
}
}
}
}
client
.search(params)
.then((result: ApiResponse) => {
console.log(result.body.hits.hits)
})
.catch((err: Error) => {
console.log(err)
})
}
run()
----

View File

@ -16,7 +16,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1', id: '1',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.', quote: 'Winter is coming.',
times: 0 times: 0
@ -26,23 +26,21 @@ async function run () {
await client.update({ await client.update({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1', id: '1',
body: { script: {
script: { lang: 'painless',
lang: 'painless', source: 'ctx._source.times++'
source: 'ctx._source.times++' // you can also use parameters
// you can also use parameters // source: 'ctx._source.times += params.count',
// source: 'ctx._source.times += params.count', // params: { count: 1 }
// params: { count: 1 }
}
} }
}) })
const { body } = await client.get({ const document = await client.get({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1' id: '1'
}) })
console.log(body) console.log(document)
} }
run().catch(console.log) run().catch(console.log)
@ -62,7 +60,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1', id: '1',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.', quote: 'Winter is coming.',
isAlive: true isAlive: true
@ -72,19 +70,17 @@ async function run () {
await client.update({ await client.update({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1', id: '1',
body: { doc: {
doc: { isAlive: false
isAlive: false
}
} }
}) })
const { body } = await client.get({ const document = await client.get({
index: 'game-of-thrones', index: 'game-of-thrones',
id: '1' id: '1'
}) })
console.log(body) console.log(document)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -15,7 +15,7 @@ const client = new Client({ node: 'http://localhost:9200' })
async function run () { async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { document: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.' quote: 'Winter is coming.'
} }
@ -24,7 +24,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
refresh: true, refresh: true,
body: { document: {
character: 'Arya Stark', character: 'Arya Stark',
quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.' quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.'
} }
@ -33,27 +33,23 @@ async function run () {
await client.updateByQuery({ await client.updateByQuery({
index: 'game-of-thrones', index: 'game-of-thrones',
refresh: true, refresh: true,
body: { script: {
script: { lang: 'painless',
lang: 'painless', source: 'ctx._source["house"] = "stark"'
source: 'ctx._source["house"] = "stark"' },
}, query: {
query: { match: {
match: { character: 'stark'
character: 'stark'
}
} }
} }
}) })
const { body } = await client.search({ const result = await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
body: { query: { match_all: {} }
query: { match_all: {} }
}
}) })
console.log(body.hits.hits) console.log(result.hits.hits)
} }
run().catch(console.log) run().catch(console.log)

View File

@ -1,72 +0,0 @@
[[extend]]
=== Extend the client
Sometimes you need to reuse the same logic, or you want to build a custom API to
allow you simplify your code. The easiest way to achieve that is by extending
the client.
NOTE: If you want to override existing methods, you should specify the
`{ force: true }` option.
[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
client.extend('supersearch', ({ makeRequest, ConfigurationError }) => {
return function supersearch (params, options) {
const {
body,
index,
method,
...querystring
} = params
// params validation
if (body == null) {
throw new ConfigurationError('Missing required parameter: body')
}
// build request object
const request = {
method: method || 'POST',
path: `/${encodeURIComponent(index)}/_search_`,
body,
querystring
}
// build request options object
const requestOptions = {
ignore: options.ignore || null,
requestTimeout: options.requestTimeout || null,
maxRetries: options.maxRetries || null,
asStream: options.asStream || false,
headers: options.headers || null
}
return makeRequest(request, requestOptions)
}
})
client.extend('utility.index', ({ makeRequest }) => {
return function _index (params, options) {
// your code
}
})
client.extend('utility.delete', ({ makeRequest }) => {
return function _delete (params, options) {
// your code
}
})
client.extend('indices.delete', { force: true }, ({ makeRequest }) => {
return function _delete (params, options) {
// your code
}
})
client.supersearch(...)
client.utility.index(...)
client.utility.delete(...)
----

View File

@ -341,23 +341,12 @@ const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
const m = client.helpers.msearch() const m = client.helpers.msearch()
// promise style API
m.search( m.search(
{ index: 'stackoverflow' }, { index: 'stackoverflow' },
{ query: { match: { title: 'javascript' } } } { query: { match: { title: 'javascript' } } }
) )
.then(result => console.log(result.body)) // or result.documents .then(result => console.log(result.body)) // or result.documents
.catch(err => console.error(err)) .catch(err => console.error(err))
// callback style API
m.search(
{ index: 'stackoverflow' },
{ query: { match: { title: 'ruby' } } },
(err, result) => {
if (err) console.error(err)
console.log(result.body)) // or result.documents
}
)
---- ----
To create a new instance of the multi search (msearch) helper, you should access To create a new instance of the multi search (msearch) helper, you should access
@ -474,11 +463,9 @@ the query string.
---- ----
const documents = await client.helpers.search({ const documents = await client.helpers.search({
index: 'stackoverflow', index: 'stackoverflow',
body: { query: {
query: { match: {
match: { title: 'javascript'
title: 'javascript'
}
} }
} }
}) })
@ -505,11 +492,9 @@ the `429` error and uses the `maxRetries` option of the client.
---- ----
const scrollSearch = client.helpers.scrollSearch({ const scrollSearch = client.helpers.scrollSearch({
index: 'stackoverflow', index: 'stackoverflow',
body: { query: {
query: { match: {
match: { title: 'javascript'
title: 'javascript'
}
} }
} }
}) })
@ -564,11 +549,9 @@ automatically adds `filter_path=hits.hits._source` to the query string.
---- ----
const scrollSearch = client.helpers.scrollDocuments({ const scrollSearch = client.helpers.scrollDocuments({
index: 'stackoverflow', index: 'stackoverflow',
body: { query: {
query: { match: {
match: { title: 'javascript'
title: 'javascript'
}
} }
} }
}) })

View File

@ -10,7 +10,6 @@ include::configuration.asciidoc[]
include::basic-config.asciidoc[] include::basic-config.asciidoc[]
include::advanced-config.asciidoc[] include::advanced-config.asciidoc[]
include::child.asciidoc[] include::child.asciidoc[]
include::extend.asciidoc[]
include::testing.asciidoc[] include::testing.asciidoc[]
include::integrations.asciidoc[] include::integrations.asciidoc[]
include::observability.asciidoc[] include::observability.asciidoc[]

View File

@ -56,6 +56,10 @@ of `^7.10.0`).
|`10.x` |`10.x`
|April 2021 |April 2021
|`7.12` (mid 2021) |`7.12` (mid 2021)
|`12.x`
|April 2022
|`8.2` (early 2022)
|=== |===
[discrete] [discrete]
@ -70,8 +74,8 @@ Elasticsearch language clients are only backwards compatible with default distri
|{es} Version |{es} Version
|Client Version |Client Version
|`main` |`8.x`
|`main` |`8.x`
|`7.x` |`7.x`
|`7.x` |`7.x`

View File

@ -4,9 +4,6 @@
This is the official Node.js client for {es}. This page gives a quick overview This is the official Node.js client for {es}. This page gives a quick overview
about the features of the client. about the features of the client.
Refer to <<breaking-changes,this page>> for breaking changes coming from the old
client.
[discrete] [discrete]
=== Features === Features
@ -23,59 +20,6 @@ client.
[discrete] [discrete]
=== Quick start === Quick start
First of all, require, then initialize the client:
[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
----
You can use both the callback API and the promise API, both behave the same way.
[source,js]
----
// promise API
const result = await client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
})
// callback API
client.search({
index: 'my-index',
body: {
query: {
match: { hello: 'world' }
}
}
}, (err, result) => {
if (err) console.log(err)
})
----
The returned value of **every** API call is formed as follows:
[source,ts]
----
{
body: object | boolean
statusCode: number
headers: object
warnings: [string]
meta: object
}
----
Let's see a complete example!
[source,js] [source,js]
---- ----
'use strict' 'use strict'
@ -87,8 +31,7 @@ async function run () {
// Let's start by indexing some data // Let's start by indexing some data
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using {es} ≤ 6 document: {
body: {
character: 'Ned Stark', character: 'Ned Stark',
quote: 'Winter is coming.' quote: 'Winter is coming.'
} }
@ -96,8 +39,7 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using {es} ≤ 6 document: {
body: {
character: 'Daenerys Targaryen', character: 'Daenerys Targaryen',
quote: 'I am the blood of the dragon.' quote: 'I am the blood of the dragon.'
} }
@ -105,29 +47,25 @@ async function run () {
await client.index({ await client.index({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using {es} ≤ 6 document: {
body: {
character: 'Tyrion Lannister', character: 'Tyrion Lannister',
quote: 'A mind needs books like a sword needs a whetstone.' quote: 'A mind needs books like a sword needs a whetstone.'
} }
}) })
// We need to force an index refresh at this point, otherwise we will not // here we are forcing an index refresh, otherwise we will not
// get any result in the consequent search // get any result in the consequent search
await client.indices.refresh({ index: 'game-of-thrones' }) await client.indices.refresh({ index: 'game-of-thrones' })
// Let's search! // Let's search!
const { body } = await client.search({ const result= await client.search({
index: 'game-of-thrones', index: 'game-of-thrones',
// type: '_doc', // uncomment this line if you are using {es} ≤ 6 query: {
body: { match: { quote: 'winter' }
query: {
match: { quote: 'winter' }
}
} }
}) })
console.log(body.hits.hits) console.log(result.hits.hits)
} }
run().catch(console.log) run().catch(console.log)
@ -181,20 +119,17 @@ const { Client: Client7 } = require('es7')
const client6 = new Client6({ node: 'http://localhost:9200' }) const client6 = new Client6({ node: 'http://localhost:9200' })
const client7 = new Client7({ node: 'http://localhost:9201' }) const client7 = new Client7({ node: 'http://localhost:9201' })
client6.info(console.log) client6.info().then(console.log, console.log)
client7.info(console.log) client7.info().then(console.log, console.log)
---- ----
Finally, if you want to install the client for the next version of {es} (the one Finally, if you want to install the client for the next version of {es} (the one
that lives in the {es} master branch), use the following command: that lives in the {es} main branch), use the following command:
[source,sh] [source,sh]
---- ----
npm install esmaster@github:elastic/elasticsearch-js npm install esmain@github:elastic/elasticsearch-js
---- ----
WARNING: This command installs the master branch of the client which is not WARNING: This command installs the main branch of the client which is not
considered stable. considered stable.
include::breaking-changes.asciidoc[]

View File

@ -2,7 +2,7 @@
=== Observability === Observability
The client does not provide a default logger, but instead it offers an event The client does not provide a default logger, but instead it offers an event
emitter interfaces to hook into internal events, such as `request` and emitter interface to hook into internal events, such as `request` and
`response`. `response`.
Correlating those events can be hard, especially if your applications have a Correlating those events can be hard, especially if your applications have a
@ -36,7 +36,7 @@ const logger = require('my-logger')()
const { Client } = require('@elastic/elasticsearch') const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
client.on('response', (err, result) => { client.diagnostic.on('response', (err, result) => {
if (err) { if (err) {
logger.error(err) logger.error(err)
} else { } else {
@ -53,7 +53,7 @@ The client emits the following events:
a|Emitted before starting serialization and compression. If you want to measure this phase duration, you should measure the time elapsed between this event and `request`. a|Emitted before starting serialization and compression. If you want to measure this phase duration, you should measure the time elapsed between this event and `request`.
[source,js] [source,js]
---- ----
client.on('serialization', (err, result) => { client.diagnostic.on('serialization', (err, result) => {
console.log(err, result) console.log(err, result)
}) })
---- ----
@ -62,7 +62,7 @@ client.on('serialization', (err, result) => {
a|Emitted before sending the actual request to {es} _(emitted multiple times in case of retries)_. a|Emitted before sending the actual request to {es} _(emitted multiple times in case of retries)_.
[source,js] [source,js]
---- ----
client.on('request', (err, result) => { client.diagnostic.on('request', (err, result) => {
console.log(err, result) console.log(err, result)
}) })
---- ----
@ -71,7 +71,7 @@ client.on('request', (err, result) => {
a|Emitted before starting deserialization and decompression. If you want to measure this phase duration, you should measure the time elapsed between this event and `response`. _(This event might not be emitted in certain situations)_. a|Emitted before starting deserialization and decompression. If you want to measure this phase duration, you should measure the time elapsed between this event and `response`. _(This event might not be emitted in certain situations)_.
[source,js] [source,js]
---- ----
client.on('deserialization', (err, result) => { client.diagnostic.on('deserialization', (err, result) => {
console.log(err, result) console.log(err, result)
}) })
---- ----
@ -80,7 +80,7 @@ client.on('deserialization', (err, result) => {
a|Emitted once {es} response has been received and parsed. a|Emitted once {es} response has been received and parsed.
[source,js] [source,js]
---- ----
client.on('response', (err, result) => { client.diagnostic.on('response', (err, result) => {
console.log(err, result) console.log(err, result)
}) })
---- ----
@ -89,7 +89,7 @@ client.on('response', (err, result) => {
a|Emitted when the client ends a sniffing request. a|Emitted when the client ends a sniffing request.
[source,js] [source,js]
---- ----
client.on('sniff', (err, result) => { client.diagnostic.on('sniff', (err, result) => {
console.log(err, result) console.log(err, result)
}) })
---- ----
@ -98,7 +98,7 @@ client.on('sniff', (err, result) => {
a|Emitted if the client is able to resurrect a dead node. a|Emitted if the client is able to resurrect a dead node.
[source,js] [source,js]
---- ----
client.on('resurrect', (err, result) => { client.diagnostic.on('resurrect', (err, result) => {
console.log(err, result) console.log(err, result)
}) })
---- ----
@ -185,14 +185,14 @@ handle this problem.
const { Client } = require('@elastic/elasticsearch') const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
client.on('request', (err, result) => { client.diagnostic.on('request', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
if (err) { if (err) {
console.log({ error: err, reqId: id }) console.log({ error: err, reqId: id })
} }
}) })
client.on('response', (err, result) => { client.diagnostic.on('response', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
if (err) { if (err) {
console.log({ error: err, reqId: id }) console.log({ error: err, reqId: id })
@ -201,10 +201,8 @@ client.on('response', (err, result) => {
client.search({ client.search({
index: 'my-index', index: 'my-index',
body: { foo: 'bar' } query: { match_all: {} }
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----
@ -232,12 +230,10 @@ You can also specify a custom id per request:
---- ----
client.search({ client.search({
index: 'my-index', index: 'my-index',
body: { foo: 'bar' } query: { match_all: {} }
}, { }, {
id: 'custom-id' id: 'custom-id'
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----
@ -252,7 +248,7 @@ can do that via the `context` option of a request:
const { Client } = require('@elastic/elasticsearch') const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
client.on('request', (err, result) => { client.diagnostic.on('request', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
const { context } = result.meta const { context } = result.meta
if (err) { if (err) {
@ -260,7 +256,7 @@ client.on('request', (err, result) => {
} }
}) })
client.on('response', (err, result) => { client.diagnostic.on('response', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
const { winter } = result.meta.context const { winter } = result.meta.context
if (err) { if (err) {
@ -270,12 +266,10 @@ client.on('response', (err, result) => {
client.search({ client.search({
index: 'my-index', index: 'my-index',
body: { foo: 'bar' } query: { match_all: {} }
}, { }, {
context: { winter: 'is coming' } context: { winter: 'is coming' }
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----
The context object can also be configured as a global option in the client The context object can also be configured as a global option in the client
@ -290,7 +284,7 @@ const client = new Client({
context: { winter: 'is coming' } context: { winter: 'is coming' }
}) })
client.on('request', (err, result) => { client.diagnostic.on('request', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
const { context } = result.meta const { context } = result.meta
if (err) { if (err) {
@ -298,7 +292,7 @@ client.on('request', (err, result) => {
} }
}) })
client.on('response', (err, result) => { client.diagnostic.on('response', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
const { winter } = result.meta.context const { winter } = result.meta.context
if (err) { if (err) {
@ -308,12 +302,10 @@ client.on('response', (err, result) => {
client.search({ client.search({
index: 'my-index', index: 'my-index',
body: { foo: 'bar' } query: { match_all: {} }
}, { }, {
context: { winter: 'has come' } context: { winter: 'has come' }
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----
@ -339,7 +331,7 @@ const child = client.child({
console.log(client.name, child.name) console.log(client.name, child.name)
client.on('request', (err, result) => { client.diagnostic.on('request', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
const { name } = result.meta const { name } = result.meta
if (err) { if (err) {
@ -347,7 +339,7 @@ client.on('request', (err, result) => {
} }
}) })
client.on('response', (err, result) => { client.diagnostic.on('response', (err, result) => {
const { id } = result.meta.request const { id } = result.meta.request
const { name } = result.meta const { name } = result.meta
if (err) { if (err) {
@ -357,17 +349,13 @@ client.on('response', (err, result) => {
client.search({ client.search({
index: 'my-index', index: 'my-index',
body: { foo: 'bar' } query: { match_all: {} }
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
child.search({ child.search({
index: 'my-index', index: 'my-index',
body: { foo: 'bar' } query: { match_all: {} }
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----
@ -397,9 +385,7 @@ client.search({
body: { foo: 'bar' } body: { foo: 'bar' }
}, { }, {
opaqueId: 'my-search' opaqueId: 'my-search'
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----
Sometimes it may be useful to prefix all the `X-Opaque-Id` headers with a Sometimes it may be useful to prefix all the `X-Opaque-Id` headers with a
@ -421,8 +407,6 @@ client.search({
body: { foo: 'bar' } body: { foo: 'bar' }
}, { }, {
opaqueId: 'my-search' opaqueId: 'my-search'
}, (err, result) => { }).then(console.log, console.log)
if (err) console.log(err)
})
---- ----

View File

@ -72,7 +72,7 @@ mock.add({
return { status: 'ok' } return { status: 'ok' }
}) })
client.info(console.log) client.info().then(console.log, console.log)
---- ----
As you can see it works closely with the client itself, once you have created a As you can see it works closely with the client itself, once you have created a
@ -129,8 +129,8 @@ mock.add({
return { count: 42 } return { count: 42 }
}) })
client.count({ index: 'foo' }, console.log) // => { count: 42 } client.count({ index: 'foo' }).then(console.log, console.log) // => { count: 42 }
client.count({ index: 'bar' }, console.log) // => { count: 42 } client.count({ index: 'bar' }).then(console.log, console.log) // => { count: 42 }
---- ----
And wildcards are supported as well. And wildcards are supported as well.

View File

@ -4,274 +4,73 @@
The client offers a first-class support for TypeScript, shipping a complete set The client offers a first-class support for TypeScript, shipping a complete set
of type definitions of Elasticsearch's API surface. of type definitions of Elasticsearch's API surface.
NOTE: If you are using TypeScript you need to use _snake_case_ style to define
the API parameters instead of _camelCase_.
Currently the client exposes two type definitions, the legacy one, which is the default
and the new one, which will be the default in the next major.
We strongly recommend to migrate to the new one as soon as possible, as the new types
are offering a vastly improved developer experience and guarantee you that your code
will always be in sync with the latest Elasticsearch features.
[discrete]
==== New type definitions
The new type definition is more advanced compared to the legacy one. In the legacy
type definitions you were expected to configure via generics both request and response
bodies. The new type definitions comes with a complete type definition for every
Elasticsearch endpoint.
For example:
[source,ts]
----
// legacy definitions
const response = await client.search<SearchResponse<Source>, SearchBody>({
index: 'test',
body: {
query: {
match: { foo: 'bar' }
}
}
})
// new definitions
const response = await client.search<Source>({
index: 'test',
body: {
query: {
match: { foo: 'bar' }
}
}
})
----
The types are not 100% complete yet. Some APIs are missing (the newest ones, e.g. EQL), The types are not 100% complete yet. Some APIs are missing (the newest ones, e.g. EQL),
and others may contain some errors, but we are continuously pushing fixes & improvements. and others may contain some errors, but we are continuously pushing fixes & improvements.
[discrete] [discrete]
==== Request & Response types ==== Example
Once you migrate to the new types, those are automatically integrated into the Elasticsearch client, you will get them out of the box.
If everything works, meaning that you wont get compiler errors, you are good to go!
The types are already correct, and there is nothing more to do.
If a type is incorrect, you should add a comment `// @ts-expect-error @elastic/elasticsearch`
telling TypeScript that you are aware of the warning and you would like to temporarily suppress it.
In this way, your code will compile until the type is fixed, and when it happens, youll only need to remove the
`// @ts-expect-error @elastic/elasticsearch` comment (TypeScript will let you know when it is time).
Finally, if the type you need is missing, youll see that the client method returns (or defines as a parameter)
a `TODO` type, which accepts any object.
Open an issue in the client repository letting us know if you encounter any problem!
If needed you can import the request and response types.
[source,ts]
----
import { Client, estypes } from '@elastic/elasticsearch'
import type { Client as NewTypes } from '@elastic/elasticsearch/api/new'
// @ts-expect-error @elastic/elasticsearch
const client: NewTypes = new Client({
node: 'http://localhost:9200'
})
interface Source {
foo: string
}
const request: estypes.IndexRequest<Source> = {
index: 'test',
body: { foo: 'bar' }
}
await client.index(request)
----
[discrete]
===== How to migrate to the new type definitions
Since the new type definitions can be considered a breaking change we couldn't add the directly to the client.
Following you will find a snippet that shows you how to override the default types with the new ones.
[source,ts] [source,ts]
---- ----
import { Client } from '@elastic/elasticsearch' import { Client } from '@elastic/elasticsearch'
import type { Client as NewTypes } from '@elastic/elasticsearch/api/new'
// @ts-expect-error @elastic/elasticsearch
const client: NewTypes = new Client({
node: 'http://localhost:9200'
})
interface Source {
foo: string
}
// try the new code completion when building a query!
const response = await client.search<Source>({
index: 'test',
body: {
query: {
match_all: {}
}
}
})
// try the new code completion when traversing a response!
const results = response.body.hits.hits.map(hit => hit._source)
// results type will be `Source[]`
console.log(results)
----
[discrete]
==== Legacy type definitions
By default event API uses
https://www.typescriptlang.org/docs/handbook/generics.html[generics] to specify
the requests and response bodies and the `meta.context`. Currently, we can't
provide those definitions, but we are working to improve this situation.
You can find a partial definition of the request types by importing
`RequestParams`, which is used by default in the client and accepts a body (when
needed) as a generic to provide a better specification.
The body defaults to `RequestBody` and `RequestNDBody`, which are defined as
follows:
[source,ts]
----
type RequestBody<T = Record<string, any>> = T | string | Buffer | ReadableStream
type RequestNDBody<T = Record<string, any>[]> = T | string | string[] | Buffer | ReadableStream
----
You can specify the response and request body in each API as follows:
[source,ts]
----
const response = await client.search<ResponseBody, RequestBody, Context>({
index: 'test',
body: {
query: {
match: { foo: 'bar' }
}
}
})
console.log(response.body)
----
You don't have to specify all the generics, but the order must be respected.
[discrete]
===== A complete example
[source,ts]
----
import {
Client,
// Object that contains the type definitions of every API method
RequestParams,
// Interface of the generic API response
ApiResponse,
} from '@elastic/elasticsearch'
const client = new Client({ node: 'http://localhost:9200' }) const client = new Client({ node: 'http://localhost:9200' })
// Define the type of the body for the Search request interface Document {
interface SearchBody { character: string
query: { quote: string
match: { foo: string }
}
}
// Complete definition of the Search response
interface ShardsResponse {
total: number;
successful: number;
failed: number;
skipped: number;
}
interface Explanation {
value: number;
description: string;
details: Explanation[];
}
interface SearchResponse<T> {
took: number;
timed_out: boolean;
_scroll_id?: string;
_shards: ShardsResponse;
hits: {
total: number;
max_score: number;
hits: Array<{
_index: string;
_type: string;
_id: string;
_score: number;
_source: T;
_version?: number;
_explanation?: Explanation;
fields?: any;
highlight?: any;
inner_hits?: any;
matched_queries?: string[];
sort?: string[];
}>;
};
aggregations?: any;
}
// Define the interface of the source object
interface Source {
foo: string
} }
async function run () { async function run () {
// All of the examples below are valid code, by default, // Let's start by indexing some data
// the request body will be `RequestBody` and response will be `Record<string, any>`. await client.index({
let response = await client.search({ index: 'game-of-thrones',
index: 'test', document: {
body: { character: 'Ned Stark',
query: { quote: 'Winter is coming.'
match: { foo: 'bar' }
}
} }
}) })
// body here is `ResponseBody`
console.log(response.body)
// The first generic is the response body await client.index({
response = await client.search<SearchResponse<Source>>({ index: 'game-of-thrones',
index: 'test', document: {
// Here the body must follow the `RequestBody` interface character: 'Daenerys Targaryen',
body: { quote: 'I am the blood of the dragon.'
query: {
match: { foo: 'bar' }
}
} }
}) })
// body here is `SearchResponse<Source>`
console.log(response.body)
response = await client.search<SearchResponse<Source>, SearchBody>({ await client.index({
index: 'test', index: 'game-of-thrones',
// Here the body must follow the `SearchBody` interface document: {
body: { character: 'Tyrion Lannister',
query: { quote: 'A mind needs books like a sword needs a whetstone.'
match: { foo: 'bar' }
}
} }
}) })
// body here is `SearchResponse<Source>`
console.log(response.body) // here we are forcing an index refresh, otherwise we will not
// get any result in the consequent search
await client.indices.refresh({ index: 'game-of-thrones' })
// Let's search!
const result= await client.search<Document>({
index: 'game-of-thrones',
query: {
match: { quote: 'winter' }
}
})
console.log(result.hits.hits)
} }
run().catch(console.log) run().catch(console.log)
---- ----
[discrete]
==== Request & Response types
You can import the full TypeScript requests & responses defintions as it follows:
[source,ts]
----
import { estypes } from '@elastic/elasticsearch'
----