diff --git a/doc/7/controllers/bulk/delete-by-query/index.md b/doc/7/controllers/bulk/delete-by-query/index.md new file mode 100644 index 000000000..8a44b45a3 --- /dev/null +++ b/doc/7/controllers/bulk/delete-by-query/index.md @@ -0,0 +1,43 @@ +--- +code: true +type: page +title: deleteByQuery +--- + +# deleteByQuery + +Deletes documents matching the provided search query. + +This is a low level route intended to bypass Kuzzle actions on document deletion, notably: + - check document write limit + - trigger [realtime notifications](/core/2/guides/essentials/real-time) + +--- + +```js +deleteByQuery(index, collection, [query], [options]); +``` + +| Argument | Type | Description | +| ------------ | ----------------- | --------------- | +| `index` |
string
| Index name | +| `collection` |
string
| Collection name | +| `query` |
object
| documents matching this search query will be deleted. Uses the [ElasticSearch Query DSL](https://www.elastic.co/guide/en/elasticsearch/reference/7.4/query-dsl.html) syntax. | +| `options` |
object
| Query options | + +### Options + +Additional query options + +| Options | Type
(default) | Description | +| ---------- | ------------------------------- | ---------------------------------------------------------------------------------- | +| `queuable` |
boolean

(`true`) | If true, queues the request during downtime, until connected to Kuzzle again | +| `refresh` |
string

(`""`) | If set to `wait_for`, waits for the change to be reflected for `search` (up to 1s) | + +## Resolves + +Resolves to the number of the deleted documents. + +## Usage + +<<< ./snippets/delete-by-query.js diff --git a/doc/7/controllers/bulk/delete-by-query/snippets/delete-by-query.js b/doc/7/controllers/bulk/delete-by-query/snippets/delete-by-query.js new file mode 100644 index 000000000..16cfba6ff --- /dev/null +++ b/doc/7/controllers/bulk/delete-by-query/snippets/delete-by-query.js @@ -0,0 +1,15 @@ +try { + const deleted = await kuzzle.bulk.deleteByQuery( + 'nyc-open-data', + 'yellow-taxi', + { + query: { + term: { capacity: 7 } + } + } + ); + + console.log(`Successfully deleted ${deleted} documents`); +} catch (error) { + console.error(error.message); +} \ No newline at end of file diff --git a/doc/7/controllers/bulk/delete-by-query/snippets/delete-by-query.test.yml b/doc/7/controllers/bulk/delete-by-query/snippets/delete-by-query.test.yml new file mode 100644 index 000000000..f1a308132 --- /dev/null +++ b/doc/7/controllers/bulk/delete-by-query/snippets/delete-by-query.test.yml @@ -0,0 +1,20 @@ +name: bulk#deleteByQuery +description: Delete 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 3 4 5; do + curl -H "Content-type: application/json" -d '{"capacity": 4}' kuzzle:7512/nyc-open-data/yellow-taxi/_create + done + + for i in 1 2 3 4 5; do + curl -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: +template: default +expected: Successfully deleted 5 documents diff --git a/src/controllers/Bulk.js b/src/controllers/Bulk.js index c11e36f4d..2c48f1ce9 100644 --- a/src/controllers/Bulk.js +++ b/src/controllers/Bulk.js @@ -5,6 +5,30 @@ class BulkController extends BaseController { super(kuzzle, 'bulk'); } + /** + * Directly deletes every documents matching the search query without: + * - applying max documents write limit + * - fetching deleted documents + * - triggering realtime notifications + * {@link https://docs.kuzzle.io/core/2/api/controllers/bulk/delete-by-query/|Official documentation} + * @param {String} index - Index name + * @param {String} collection - Collection name + * @param {Object[]} query - Query matching documents to delete + * @param {Object} [options] - Additional options + * @returns {Promise} + */ + deleteByQuery(index, collection, query = {}, options = {}) { + const request = { + index, + collection, + body: query, + action: 'deleteByQuery' + }; + + return this.query(request, options) + .then(response => response.result.deleted); + } + /** * Creates, updates or deletes large amounts of documents as fast as possible. * {@link https://docs.kuzzle.io/core/2/api/controllers/bulk/import/|Official documentation} diff --git a/src/protocols/routes.json b/src/protocols/routes.json index 1a6836f0d..df55cbad4 100644 --- a/src/protocols/routes.json +++ b/src/protocols/routes.json @@ -58,6 +58,10 @@ } }, "bulk": { + "deleteByQuery": { + "url": "/:index/:collection/_bulk/_query", + "verb": "DELETE" + }, "import": { "verb": "POST", "url": "/:index/:collection/_bulk" diff --git a/test/controllers/bulk.test.js b/test/controllers/bulk.test.js index 8df3e1e3f..750a6792a 100644 --- a/test/controllers/bulk.test.js +++ b/test/controllers/bulk.test.js @@ -20,6 +20,27 @@ describe('Bulk Controller', () => { kuzzle.bulk = new BulkController(kuzzle); }); + describe('deleteByQuery', () => { + it('should call document/deleteByQuery query and return a Promise which resolves the list of deleted document ids', () => { + kuzzle.query.resolves({ result: { deleted: 3 } }); + const options = {refresh: 'wait_for'}; + return kuzzle.bulk.deleteByQuery('index', 'collection', { query: { match: { foo: 'bar' } } }, options) + .then(res => { + should(kuzzle.query) + .be.calledOnce() + .be.calledWith({ + controller: 'bulk', + action: 'deleteByQuery', + index: 'index', + collection: 'collection', + body: {query: {match: {foo: 'bar' }}} + }, options); + + should(res).be.an.Number(); + should(res).be.equal(3); + }); + }); + }); describe('import', () => { it('should call bulk/import query with the bulk data and return a Promise which resolves json object', () => {