@jmaitrehenry/elastic-builder
Version:
A JavaScript implementation of the elasticsearch Query DSL
1,004 lines (889 loc) • 35.2 kB
JavaScript
'use strict';
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var has = require('lodash.has'),
isNil = require('lodash.isnil'),
isEmpty = require('lodash.isempty');
var Query = require('./query'),
Aggregation = require('./aggregation'),
Suggester = require('./suggester'),
Rescore = require('./rescore'),
Sort = require('./sort'),
Highlight = require('./highlight'),
InnerHits = require('./inner-hits');
var _require = require('./util'),
checkType = _require.checkType,
setDefault = _require.setDefault,
recursiveToJSON = _require.recursiveToJSON;
/**
* Helper function to call `recursiveToJSON` on elements of array and assign to object.
*
* @private
*
* @param {Array} arr
* @returns {Object}
*/
function recMerge(arr) {
return Object.assign.apply(Object, [{}].concat((0, _toConsumableArray3.default)(recursiveToJSON(arr))));
}
/**
* The `RequestBodySearch` object provides methods generating an elasticsearch
* search request body. The search request can be executed with a search DSL,
* which includes the Query DSL, within its body.
*
* [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html)
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .from(0)
* .size(10);
*
* reqBody.toJSON();
* {
* "query": { "term": { "user": "kimchy" } },
* "from": 0,
* "size": 10
* }
*
* @example
* // Query and aggregation
* const reqBody = esb.requestBodySearch()
* .query(esb.matchQuery('business_type', 'shop'))
* .agg(
* esb.geoBoundsAggregation('viewport', 'location').wrapLongitude(true)
* );
*
* @example
* // Query, aggregation with nested
* const reqBody = esb.requestBodySearch()
* .query(esb.matchQuery('crime', 'burglary'))
* .agg(
* esb.termsAggregation('towns', 'town').agg(
* esb.geoCentroidAggregation('centroid', 'location')
* )
* );
*/
var RequestBodySearch = function () {
// eslint-disable-next-line require-jsdoc
function RequestBodySearch() {
(0, _classCallCheck3.default)(this, RequestBodySearch);
// Maybe accept some optional parameter?
this._body = {};
this._aggs = [];
this._suggests = [];
this._suggestText = null;
}
/**
* Define query on the search request body using the Query DSL.
*
* @param {Query} query
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
(0, _createClass3.default)(RequestBodySearch, [{
key: 'query',
value: function query(_query) {
checkType(_query, Query);
this._body.query = _query;
return this;
}
/**
* Sets aggregation on the request body.
* Alias for method `aggregation`
*
* @param {Aggregation} agg Any valid `Aggregation`
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
* @throws {TypeError} If `agg` is not an instance of `Aggregation`
*/
}, {
key: 'agg',
value: function agg(_agg) {
return this.aggregation(_agg);
}
/**
* Sets aggregation on the request body.
*
* @param {Aggregation} agg Any valid `Aggregation`
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
* @throws {TypeError} If `agg` is not an instance of `Aggregation`
*/
}, {
key: 'aggregation',
value: function aggregation(agg) {
checkType(agg, Aggregation);
this._aggs.push(agg);
return this;
}
/**
* Sets multiple nested aggregation items.
* Alias for method `aggregations`
*
* @param {Array<Aggregation>} aggs Array of valid {@link Aggregation} items
* @returns {Aggregation} returns `this` so that calls can be chained.
* @throws {TypeError} If `aggs` is not an instance of `Array`
* @throws {TypeError} If `aggs` contains instances not of type `Aggregation`
*/
}, {
key: 'aggs',
value: function aggs(_aggs) {
return this.aggregations(_aggs);
}
/**
* Sets multiple nested aggregation items.
* This method accepts an array to set multiple nested aggregations in one call.
*
* @param {Array<Aggregation>} aggs Array of valid {@link Aggregation} items
* @returns {Aggregation} returns `this` so that calls can be chained.
* @throws {TypeError} If `aggs` is not an instance of `Array`
* @throws {TypeError} If `aggs` contains instances not of type `Aggregation`
*/
}, {
key: 'aggregations',
value: function aggregations(aggs) {
var _this = this;
checkType(aggs, Array);
aggs.forEach(function (agg) {
return _this.aggregation(agg);
});
return this;
}
/**
* Sets suggester on the request body.
*
* @example
* const req = esb.requestBodySearch()
* .query(esb.matchQuery('message', 'trying out elasticsearch'))
* .suggest(
* esb.termSuggester(
* 'my-suggestion',
* 'message',
* 'tring out Elasticsearch'
* )
* );
*
* @param {Suggester} suggest Any valid `Suggester`
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
* @throws {TypeError} If `suggest` is not an instance of `Suggester`
*/
}, {
key: 'suggest',
value: function suggest(_suggest) {
checkType(_suggest, Suggester);
this._suggests.push(_suggest);
return this;
}
/**
* Sets the global suggest text to avoid repetition for multiple suggestions.
*
* @example
* const req = esb.requestBodySearch()
* .suggestText('tring out elasticsearch')
* .suggest(esb.termSuggester('my-suggest-1', 'message'))
* .suggest(esb.termSuggester('my-suggest-2', 'user'));
*
* @param {string} txt Global suggest text
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'suggestText',
value: function suggestText(txt) {
this._suggestText = txt;
return this;
}
/**
* Sets a search timeout, bounding the search request to be executed within
* the specified time value and bail with the hits accumulated up to that
* point when expired.
*
* @param {string} timeout Duration can be specified using
* [time units](https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units)
* Defaults to no timeout.
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'timeout',
value: function timeout(_timeout) {
this._body.timeout = _timeout;
return this;
}
/**
* To retrieve hits from a certain offset.
*
* @param {number} from Defaults to 0.
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'from',
value: function from(_from) {
this._body.from = _from;
return this;
}
/**
* The number of hits to return. If you do not care about getting some hits back
* but only about the number of matches and/or aggregations, setting the value
* to 0 will help performance.
*
* @param {number} size Defaults to 10.
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'size',
value: function size(_size) {
this._body.size = _size;
return this;
}
/**
* The maximum number of documents to collect for each shard, upon reaching which
* the query execution will terminate early. If set, the response will have a
* boolean field `terminated_early` to indicate whether the query execution has
* actually terminated early.
*
* @param {number} numberOfDocs Maximum number of documents to collect for each shard.
* Defaults to no limit.
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'terminateAfter',
value: function terminateAfter(numberOfDocs) {
this._body.terminate_after = numberOfDocs;
return this;
}
/**
* Allows to add sort on specific field. The sort can be reversed as well.
* The sort is defined on a per field level, with special field name for `_score` to
* sort by score, and `_doc` to sort by index order.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .sort(esb.sort('post_date', 'asc'))
* .sort(esb.sort('user'))
* .sorts([
* esb.sort('name', 'desc'),
* esb.sort('age', 'desc'),
* esb.sort('_score')
* ]);
*
* @param {Sort} sort
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
* @throws {TypeError} If parameter `sort` is not an instance of `Sort`.
*/
}, {
key: 'sort',
value: function sort(_sort) {
checkType(_sort, Sort);
setDefault(this._body, 'sort', []);
this._body.sort.push(_sort);
return this;
}
/**
* Allows to add multiple sort on specific fields. Each sort can be reversed as well.
* The sort is defined on a per field level, with special field name for _score to
* sort by score, and _doc to sort by index order.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .sort(esb.sort('post_date', 'asc'))
* .sort(esb.sort('user'))
* .sorts([
* esb.sort('name', 'desc'),
* esb.sort('age', 'desc'),
* esb.sort('_score')
* ]);
*
* @param {Array<Sort>} sorts Arry of sort
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
* @throws {TypeError} If any item in parameter `sorts` is not an instance of `Sort`.
*/
}, {
key: 'sorts',
value: function sorts(_sorts) {
var _this2 = this;
_sorts.forEach(function (sort) {
return _this2.sort(sort);
});
return this;
}
/**
* When sorting on a field, scores are not computed. By setting `track_scores` to true,
* scores will still be computed and tracked.
*
* @example
* const reqBody = esb.requestBodySearch()
* .trackScores(true)
* .sorts([
* esb.sort('post_date', 'desc'),
* esb.sort('name', 'desc'),
* esb.sort('age', 'desc')
* ])
* .query(esb.termQuery('user', 'kimchy'));
*
* @param {boolean} enable
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'trackScores',
value: function trackScores(enable) {
this._body.track_scores = enable;
return this;
}
/**
* The `track_total_hits` parameter allows you to control how the total number of hits
* should be tracked. Passing `false` can increase performance in some situations.
* (Added in elasticsearch@7)
*
* Pass `true`, `false`, or the upper limit (default: `10000`) of hits you want tracked.
*
* @param {boolean|number} enableOrLimit
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'trackTotalHits',
value: function trackTotalHits(enableOrLimit) {
this._body.track_total_hits = enableOrLimit;
return this;
}
/**
* Allows to control how the `_source` field is returned with every hit.
* You can turn off `_source` retrieval by passing `false`.
* It also accepts one(string) or more wildcard(array) patterns to control
* what parts of the `_source` should be returned
* An object can also be used to specify the wildcard patterns for `includes` and `excludes`.
*
* @example
* // To disable `_source` retrieval set to `false`:
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .source(false);
*
* @example
* // The `_source` also accepts one or more wildcard patterns to control what
* // parts of the `_source` should be returned:
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .source('obj.*');
*
* // OR
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .source([ 'obj1.*', 'obj2.*' ]);
*
* @example
* // For complete control, you can specify both `includes` and `excludes` patterns:
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .source({
* 'includes': [ 'obj1.*', 'obj2.*' ],
* 'excludes': [ '*.description' ]
* });
*
* @param {boolean|string|Array|Object} source
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'source',
value: function source(_source) {
this._body._source = _source;
return this;
}
/**
* The `stored_fields` parameter is about fields that are explicitly marked as stored in the mapping.
* Selectively load specific stored fields for each document represented by a search hit
* using array of stored fields.
* An empty array will cause only the `_id` and `_type` for each hit to be returned.
* To disable the stored fields (and metadata fields) entirely use: `_none_`
*
* @example
* // Selectively load specific stored fields for each document
* // represented by a search hit
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .storedFields(['user', 'postDate']);
*
* @example
* // Return only the `_id` and `_type` to be returned:
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .storedFields([]);
*
* @example
* // Disable the stored fields (and metadata fields) entirely
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .storedFields('_none_');
*
* @param {Array|string} fields
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'storedFields',
value: function storedFields(fields) {
this._body.stored_fields = fields;
return this;
}
/**
* Computes a document property dynamically based on the supplied `script`.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeField(
* 'sessionId-name',
* esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['name'].value)`
* )
* )
*
* @example
* // runtime fields can also be used in query aggregation
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeField(
* 'sessionId-eventName',
* esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['eventName'].value)`,
* )
* )
* .agg(esb.cardinalityAggregation('uniqueCount', `sessionId-eventName`)),;
*
* @param {string} runtimeFieldName
* @param {RuntimeField} instance of `RuntimeField`
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'runtimeMapping',
value: function runtimeMapping(runtimeMappingName, runtimeField) {
setDefault(this._body, 'runtime_mappings', {});
this._body.runtime_mappings[runtimeMappingName] = runtimeField;
return this;
}
/**
* Computes one or more document properties dynamically based on supplied `RuntimeField`s.
*
* @example
* const fieldA = esb.runtimeField(
* 'keyword',
* `emit(doc['session_id'].value + '::' + doc['name'].value)`,
* 'sessionId-name'
* );
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .runtimeFields({
* 'sessionId-name': fieldA,
* })
*
* @param {Object} runtimeFields Object with `runtimeFieldName` as key and `RuntimeField` instance as the value.
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'runtimeMappings',
value: function runtimeMappings(_runtimeMappings) {
var _this3 = this;
checkType(_runtimeMappings, Object);
Object.keys(_runtimeMappings).forEach(function (runtimeMappingName) {
return _this3.runtimeMapping(runtimeMappingName, _runtimeMappings[runtimeMappingName]);
});
return this;
}
/**
* Computes a document property dynamically based on the supplied `Script`.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .scriptField(
* 'test1',
* esb.script('inline', "doc['my_field_name'].value * 2").lang('painless')
* )
* .scriptField(
* 'test2',
* esb.script('inline', "doc['my_field_name'].value * factor")
* .lang('painless')
* .params({ factor: 2.0 })
* );
*
* @example
* // Script fields can also access the actual `_source` document and extract
* // specific elements to be returned from it by using `params['_source']`.
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .scriptField('test1', "params['_source']['message']");
*
* @param {string} scriptFieldName
* @param {string|Script} script string or instance of `Script`
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'scriptField',
value: function scriptField(scriptFieldName, script) {
setDefault(this._body, 'script_fields', {});
this._body.script_fields[scriptFieldName] = { script: script };
return this;
}
/**
* Sets given dynamic document properties to be computed using supplied `Script`s.
*
* Object should have `scriptFieldName` as key and `script` as the value.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .scriptFields({
* test1: esb
* .script('inline', "doc['my_field_name'].value * 2")
* .lang('painless'),
* test2: esb
* .script('inline', "doc['my_field_name'].value * factor")
* .lang('painless')
* .params({ factor: 2.0 })
* });
*
* @example
* // Script fields can also access the actual `_source` document and extract
* // specific elements to be returned from it by using `params['_source']`.
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .scriptFields({ test1: "params['_source']['message']" });
* @param {Object} scriptFields Object with `scriptFieldName` as key and `script` as the value.
* @returns {TopHitsAggregation} returns `this` so that calls can be chained
*/
}, {
key: 'scriptFields',
value: function scriptFields(_scriptFields) {
var _this4 = this;
checkType(_scriptFields, Object);
Object.keys(_scriptFields).forEach(function (scriptFieldName) {
return _this4.scriptField(scriptFieldName, _scriptFields[scriptFieldName]);
});
return this;
}
/**
* Allows to return the doc value representation of a field for each hit.
* Doc value fields can work on fields that are not stored.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .docvalueFields(['test1', 'test2']);
*
* @param {Array<string>} fields
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'docvalueFields',
value: function docvalueFields(fields) {
this._body.docvalue_fields = fields;
return this;
}
/**
* The `post_filter` is applied to the search hits at the very end of a search request,
* after aggregations have already been calculated.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.boolQuery().filter(esb.termQuery('brand', 'gucci')))
* .agg(esb.termsAggregation('colors', 'color'))
* .agg(
* esb.filterAggregation(
* 'color_red',
* esb.termQuery('color', 'red')
* ).agg(esb.termsAggregation('models', 'model'))
* )
* .postFilter(esb.termQuery('color', 'red'));
*
* @param {Query} filterQuery The filter to be applied after aggregation.
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'postFilter',
value: function postFilter(filterQuery) {
checkType(filterQuery, Query);
this._body.post_filter = filterQuery;
return this;
}
/**
* Allows to highlight search results on one or more fields. The implementation
* uses either the lucene `plain` highlighter, the fast vector highlighter (`fvh`)
* or `postings` highlighter.
*
* Note: The `postings` highlighter has been removed in elasticsearch 6.0.
* The `unified` highlighter outputs the same highlighting when
* `index_options` is set to `offsets`.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchAllQuery())
* .highlight(esb.highlight('content'));
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(
* esb.percolateQuery('query', 'doctype').document({
* message: 'The quick brown fox jumps over the lazy dog'
* })
* )
* .highlight(esb.highlight('message'));
*
* @param {Highlight} highlight
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'highlight',
value: function highlight(_highlight) {
checkType(_highlight, Highlight);
this._body.highlight = _highlight;
return this;
}
/**
* Rescoring can help to improve precision by reordering just the top (eg 100 - 500)
* documents returned by the `query` and `post_filter` phases, using a secondary
* (usually more costly) algorithm, instead of applying the costly algorithm to
* all documents in the index.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchQuery('message', 'the quick brown').operator('or'))
* .rescore(
* esb.rescore(
* 50,
* esb.matchPhraseQuery('message', 'the quick brown').slop(2)
* )
* .queryWeight(0.7)
* .rescoreQueryWeight(1.2)
* );
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchQuery('message', 'the quick brown').operator('or'))
* .rescore(
* esb.rescore(
* 100,
* esb.matchPhraseQuery('message', 'the quick brown').slop(2)
* )
* .queryWeight(0.7)
* .rescoreQueryWeight(1.2)
* )
* .rescore(
* esb.rescore(
* 10,
* esb.functionScoreQuery().function(
* esb.scriptScoreFunction(
* esb.script('inline', 'Math.log10(doc.likes.value + 2)')
* )
* )
* ).scoreMode('multiply')
* );
*
* @param {Rescore} rescore
* @returns {RequestBodySearch} returns `this` so that calls can be chained
* @throws {TypeError} If `query` is not an instance of `Rescore`
*/
}, {
key: 'rescore',
value: function rescore(_rescore) {
checkType(_rescore, Rescore);
if (has(this._body, 'rescore')) {
if (!Array.isArray(this._body.rescore)) {
this._body.rescore = [this._body.rescore];
}
this._body.rescore.push(_rescore);
} else this._body.rescore = _rescore;
return this;
}
// TODO: Scroll related changes
// Maybe only slice needs to be supported.
/**
* Enables explanation for each hit on how its score was computed.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .explain(true);
*
* @param {boolean} enable
* @returns {RequestBodySearch} returns `this` so that calls can be chained
*/
}, {
key: 'explain',
value: function explain(enable) {
this._body.explain = enable;
return this;
}
/**
* Returns a version for each search hit.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .version(true);
*
* @param {boolean} enable
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'version',
value: function version(enable) {
this._body.version = enable;
return this;
}
/**
* Allows to configure different boost level per index when searching across
* more than one indices. This is very handy when hits coming from one index
* matter more than hits coming from another index.
*
* Alias for method `indicesBoost`.
*
* @example
* const reqBody = esb.requestBodySearch()
* .indexBoost('alias1', 1.4)
* .indexBoost('index*', 1.3);
*
* @param {string} index Index windcard expression or alias
* @param {number} boost
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'indexBoost',
value: function indexBoost(index, boost) {
return this.indicesBoost(index, boost);
}
/**
* Allows to configure different boost level per index when searching across
* more than one indices. This is very handy when hits coming from one index
* matter more than hits coming from another index.
*
* @example
* const reqBody = esb.requestBodySearch()
* .indicesBoost('alias1', 1.4)
* .indicesBoost('index*', 1.3);
*
* @param {string} index Index windcard expression or alias
* @param {number} boost
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'indicesBoost',
value: function indicesBoost(index, boost) {
setDefault(this._body, 'indices_boost', []);
this._body.indices_boost.push((0, _defineProperty3.default)({}, index, boost));
return this;
}
/**
* Exclude documents which have a `_score` less than the minimum specified in `min_score`.
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.termQuery('user', 'kimchy'))
* .minScore(0.5);
*
* @param {number} score
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'minScore',
value: function minScore(score) {
this._body.min_score = score;
return this;
}
/**
* Allows to collapse search results based on field values. The collapsing
* is done by selecting only the top sorted document per collapse key.
*
* The field used for collapsing must be a single valued `keyword` or `numeric`
* field with `doc_values` activated
*
* @example
* const reqBody = esb.requestBodySearch()
* .query(esb.matchQuery('message', 'elasticsearch'))
* .collapse('user')
* .sort(esb.sort('likes'))
* .from(10);
*
* @example
* // Expand each collapsed top hits with the `inner_hits` option:
* const reqBody = esb.requestBodySearch()
* .query(esb.matchQuery('message', 'elasticsearch'))
* .collapse(
* 'user',
* esb.innerHits('last_tweets')
* .size(5)
* .sort(esb.sort('date', 'asc')),
* 4
* )
* .sort(esb.sort('likes'))
* .from(10);
*
* @param {string} field
* @param {InnerHits=} innerHits Allows to expand each collapsed top hits.
* @param {number=} maxConcurrentGroupRequests The number of concurrent
* requests allowed to retrieve the inner_hits' per group
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
* @throws {TypeError} If `innerHits` is not an instance of `InnerHits`
*/
}, {
key: 'collapse',
value: function collapse(field, innerHits, maxConcurrentGroupRequests) {
var collapse = this._body.collapse = { field: field };
if (!isNil(innerHits)) {
checkType(innerHits, InnerHits);
collapse.inner_hits = innerHits;
collapse.max_concurrent_group_searches = maxConcurrentGroupRequests;
}
return this;
}
/**
* Allows to use the results from the previous page to help the retrieval
* of the next page. The `search_after` parameter provides a live cursor.
*
* The parameter `from` must be set to `0` (or `-1`) when `search_after` is used.
*
* @example
* const reqBody = esb.requestBodySearch()
* .size(10)
* .query(esb.matchQuery('message', 'elasticsearch'))
* .searchAfter(1463538857, 'tweet#654323')
* .sorts([esb.sort('date', 'asc'), esb.sort('_uid', 'desc')]);
*
* @param {Array<*>} values The `sort values` of the last document to retrieve
* the next page of results
* @returns {RequestBodySearch} returns `this` so that calls can be chained.
*/
}, {
key: 'searchAfter',
value: function searchAfter(values) {
this._body.search_after = values;
return this;
}
/**
* Override default `toJSON` to return DSL representation for the request body search
*
* @override
* @returns {Object} returns an Object which maps to the elasticsearch query DSL
*/
}, {
key: 'toJSON',
value: function toJSON() {
var dsl = recursiveToJSON(this._body);
if (!isEmpty(this._aggs)) dsl.aggs = recMerge(this._aggs);
if (!isEmpty(this._suggests) || !isNil(this._suggestText)) {
dsl.suggest = recMerge(this._suggests);
if (!isNil(this._suggestText)) {
dsl.suggest.text = this._suggestText;
}
}
return dsl;
}
}]);
return RequestBodySearch;
}();
module.exports = RequestBodySearch;