Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions doc/7/controllers/bulk/update-by-query/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
code: true
type: page
title: updateByQuery
description: Updates documents matching query
---

# updateByQuery

<SinceBadge version="Kuzzle 2.11.0"/>
<SinceBadge version="auto-version"/>

Updates documents matching the provided search query.

Kuzzle uses the [ElasticSearch Query DSL](https://www.elastic.co/guide/en/elasticsearch/reference/7.4/query-dsl.html) syntax.

An empty or null query will match all documents in the collection.

<br/>

```js
updateByQuery(index, collection, searchQuery, changes, [options])
```

| Argument | Type | Description |
|---------------|-------------------|-------------------------------------------|
| `index` | <pre>string</pre> | Index name |
| `collection` | <pre>string</pre> | Collection name |
| `searchQuery` | <pre>object</pre> | Query to match |
Copy link
Contributor

Choose a reason for hiding this comment

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

Should match the method parameter name query

| `changes` | <pre>object</pre> | Partial changes to apply to the documents |
| `options` | <pre>object</pre> | Optional parameters |

---

### options

Additional query options.

| Options | Type<br/>(default) | Description |
|-----------|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| `refresh` | <pre>string</pre><br/>(`""`) | If set to `wait_for`, waits for the change to be reflected for `search` (up to 1s) |

## Resolves

Returns the number of updated documents.

## Usage

<<< ./snippets/update-by-query.js
17 changes: 17 additions & 0 deletions doc/7/controllers/bulk/update-by-query/snippets/update-by-query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
try {
const result = await kuzzle.bulk.updateByQuery(
'nyc-open-data',
'yellow-taxi',
{
match: {
capacity: 4
}
},
{ capacity: 42 });
console.log(result);
/**
* 2
*/
} catch (error) {
console.log(error.message);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: bulk#updateByQuery
description: Update documents matching query
hooks:
before: |
curl -XDELETE kuzzle:7512/nyc-open-data
curl -XPOST kuzzle:7512/nyc-open-data/_create
curl -XPUT kuzzle:7512/nyc-open-data/yellow-taxi
for i in 1 2 ; do
curl --fail -H "Content-type: application/json" -d '{"capacity": 4}' kuzzle:7512/nyc-open-data/yellow-taxi/document_$i/_create
done
for i in 1 2 3 4 5; do
curl --fail -H "Content-type: application/json" -d '{"capacity": 7}' kuzzle:7512/nyc-open-data/yellow-taxi/_create
done
curl -XPOST kuzzle:7512/nyc-open-data/yellow-taxi/_refresh
after:
- curl -XDELETE kuzzle:7512/nyc-open-data
template: default
expected: 2
92 changes: 92 additions & 0 deletions doc/7/controllers/document/m-upsert/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
code: true
type: page
title: mUpsert
description: Update documents
---

# mUpsert

<SinceBadge version="Kuzzle 2.11.0"/>
<SinceBadge version="auto-version"/>

Applies partial changes to multiple documents. If a document doesn't already exist, a new document is created.

You can set the `retryOnConflict` optional argument (with a retry count), to tell Kuzzle to retry the failing updates the specified amount of times before rejecting the request with an error.

<br/>

```js
mUpsert(index, collection, documents, [options]);
```

| Argument | Type | Description |
|--------------|---------------------|------------------------------|
| `index` | <pre>string</pre> | Index name |
| `collection` | <pre>string</pre> | Collection name |
| `documents` | <pre>object[]</pre> | Array of documents to update |
| `options` | <pre>object</pre> | Query options |


### documents

`documents` is an array of object which each object represents a document. Fields `_id` and `changes` is always mandatory while `default` is optional.
Example:

```js
[
{
"_id": "<documentId>",
"changes": {
// document partial changes
},
"default": {
// optional: document fields to add to the "update" part if the document
// is created
}
},
{
"_id": "<anotherDocumentId>",
"changes": {
// document partial changes
},
}
]
```

### Options

Additional query options

| Options | Type<br/>(default) | Description |
|-------------------|----------------------------------|------------------------------------------------------------------------------------------|
| `queuable` | <pre>boolean</pre><br/>(`true`) | If true, queues the request during downtime, until connected to Kuzzle again |
| `refresh` | <pre>string</pre><br/>(`""`) | If set to `wait_for`, waits for the change to be reflected for `search` (up to 1s) |
| `retryOnConflict` | <pre>int</pre><br/>(`0`) | The number of times the database layer should retry in case of version conflict |
| `silent` | <pre>boolean</pre><br/>(`false`) | If `true`, then Kuzzle will not generate notifications <SinceBadge version="7.5.3"/> |

## Resolves

Returns an object containing 2 arrays: `successes` and `errors`

Each updated document is an object of the `successes` array with the following properties:

| Name | Type | Description |
|------------|-------------------|--------------------------------------------------------|
| `_id` | <pre>string</pre> | Document ID |
| `status` | <pre>number</pre> | HTTP error status |
| `created` | <pre>boolean</pre>| `true` if the document has been created |
| `_version` | <pre>number</pre> | Version of the document in the persistent data storage |
| `_source` | <pre>object</pre> | Document content |

Each errored document is an object of the `errors` array with the following properties:

| Name | Type | Description |
|------------|-------------------|-------------------------------|
| `document` | <pre>object</pre> | Document that cause the error |
| `status` | <pre>number</pre> | HTTP error status |
| `reason` | <pre>string</pre> | Human readable reason |

## Usage

<<< ./snippets/m-upsert.js
44 changes: 44 additions & 0 deletions doc/7/controllers/document/m-upsert/snippets/m-upsert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const doc1 = { capacity: 4 };
const doc2 = { capacity: 7 };

try {
await kuzzle.document.create('nyc-open-data', 'yellow-taxi', doc1, 'some-id');
await kuzzle.document.create('nyc-open-data', 'yellow-taxi', doc2, 'some-other-id');

const documents = [
{
_id: 'some-id',
changes: { category: 'sedan' }
},
{
_id: 'some-other-id',
changes: { category: 'limousine' },
default: { capacity: 8 }
}
];

const response = await kuzzle.document.mUpsert(
'nyc-open-data',
'yellow-taxi',
documents
);

console.log(response);
/*
{ successes:
[ { _id: 'some-id',
_source: { _kuzzle_info: [Object], category: 'sedan' },
_version: 2,
created: false,
status: 200 },
{ _id: 'some-other-id',
_source: { _kuzzle_info: [Object], category: 'limousine', capacity: 8 },
_version: 1,
created: true,
status: 200 } ],
errors: [] }
*/
console.log('Success');
} catch (error) {
console.error(error.message);
}
10 changes: 10 additions & 0 deletions doc/7/controllers/document/m-upsert/snippets/m-upsert.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: document#mUpsert
description: Update documents
hooks:
before: |
curl -XDELETE kuzzle:7512/nyc-open-data
curl -XPOST kuzzle:7512/nyc-open-data/_create
curl -XPUT kuzzle:7512/nyc-open-data/yellow-taxi
after:
template: default
expected: Success
34 changes: 34 additions & 0 deletions src/controllers/Bulk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,40 @@ export class BulkController extends BaseController {
.then(response => response.result);
}

/**
* Updates documents matching the provided search query.
*
* @see https://docs.kuzzle.io/sdk/js/7/controllers/bulk/update-by-query/
*
* @param index Index name
* @param collection Collection name
* @param query Query to match
* @param changes Partial changes to apply to the documents
* @param options Additional options
* - `refresh` If set to `wait_for`, Kuzzle will not respond until the API key is indexed
*
* @returns The number of updated documents
*/
updateByQuery(
index: string,
collection: string,
query: JSONObject,
changes: JSONObject,
options: {
refresh?: 'wait_for'
} = {}
): Promise<number> {
const request = {
index,
collection,
body: { query, changes },
action: 'updateByQuery'
};

return this.query(request, options)
.then(response => response.result.updated);
}

/**
* Creates or replaces a document directly into the storage engine.
*
Expand Down
75 changes: 75 additions & 0 deletions src/controllers/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,81 @@ export class DocumentController extends BaseController {
.then(response => response.result);
}

/**
* Applies partial updates to multiple documents.
*
* If a document doesn't already exist, a new document is created.
* @see https://docs.kuzzle.io/sdk/js/7/controllers/document/m-upsert/
*
* @param index Index name
* @param collection Collection name
* @param documents Documents to update
* @param options Additional options
* - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
* - `refresh` If set to `wait_for`, Kuzzle will not respond until the API key is indexed
* - `silent` If true, then Kuzzle will not generate notifications
* - `retryOnConflict` Number of times the database layer should retry in case of version conflict
*
* @returns An object containing 2 arrays: "successes" and "errors"
*/
mUpsert (
index: string,
collection: string,
documents: Array<{
/**
* Document ID
*/
_id: string;
/**
* Partial content of the document to update
*/
changes: JSONObject;
/**
* Fields to add to the document if it gets created
*/
default: JSONObject
}>,
options: {
queuable?: boolean,
refresh?: 'wait_for',
silent?: boolean,
retryOnConflict?: number,
} = {}
): Promise<{
/**
* Array of successfully updated documents
*/
successes: Array<Document>;
/**
* Array of failed creation
*/
errors: Array<{
/**
* Document that cause the error
*/
document: Document;
/**
* HTTP error status
*/
status: number;
/**
* Human readable reason
*/
reason: string;
}>;
}> {
const request = {
index,
collection,
body: { documents },
action: 'mUpsert',
silent: options.silent,
};

return this.query(request, options)
.then(response => response.result);
}

/**
* Replaces the content of an existing document.
*
Expand Down
8 changes: 8 additions & 0 deletions src/protocols/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
"mWrite": {
"verb": "POST",
"url": "/:index/:collection/_mWrite"
},
"updateByQuery": {
"url": "/:index/:collection/_bulk/_query",
"verb": "PATCH"
}
},
"document": {
Expand Down Expand Up @@ -124,6 +128,10 @@
"url": "/:index/:collection/_mUpdate",
"verb": "PUT"
},
"mUpsert": {
"url": "/:index/:collection/_mUpsert",
"verb": "POST"
},
"replace": {
"url": "/:index/:collection/:_id/_replace",
"verb": "PUT"
Expand Down