Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/danpaz/bodybuilder

An elasticsearch query body builder :muscle:
https://github.com/danpaz/bodybuilder

builder elasticsearch hacktoberfest javascript querydsl

Last synced: 1 day ago
JSON representation

An elasticsearch query body builder :muscle:

Awesome Lists containing this project

README

        

# bodybuilder
[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors)
[![npm version](https://badge.fury.io/js/bodybuilder.svg)](https://www.npmjs.com/package/bodybuilder)
[![Build Status](https://travis-ci.org/danpaz/bodybuilder.svg?branch=master)](https://travis-ci.org/danpaz/bodybuilder)

An elasticsearch query body builder. Easily build complex queries for
elasticsearch with a simple, predictable api.

![bodybuilder](img/bodybuilder.jpeg)

# Documentation

**Check out the [API documentation](http://bodybuilder.js.org/docs)** for details and examples.

Use https://bodybuilder.js.org/ to test your constructions.

## Elasticsearch compatibility

Currently aims to support the full elasticsearch query DSL for all versions.

The elasticsearch 1.x query DSL is supported by providing a `v1` argument
when calling the `build` function.

## Install

npm install bodybuilder --save

## Usage

```js
var bodybuilder = require('bodybuilder')
var body = bodybuilder().query('match', 'message', 'this is a test')
body.build() // Build 2.x or greater DSL (default)
body.build('v1') // Build 1.x DSL
```

For each elasticsearch query body, create an instance of `bodybuilder`, apply
the desired query/filter/aggregation clauses, and call `build` to retrieve the
built query body.

## REPL

Try it out on the command line using the node REPL:

# Start the repl
node ./node_modules/bodybuilder/repl.js
# The builder is available in the context variable bodybuilder
bodybuilder > bodybuilder().query('match', 'message', 'this is a test').build()

### Queries

```js
bodybuilder().query([arguments])
```

Creates a query of type `queryType`.

#### Arguments

The specific arguments depend on the type of query, but typically follow this
pattern:

* `queryType` - The name of the query, such as `'term'` or `'prefix'`.
* `fieldToQuery` - The name of the field in your index to query over.
* `searchTerm` - The string to search for.

```js
var body = bodybuilder().query('match', 'message', 'this is a test').build()
// body == {
// query: {
// match: {
// message: 'this is a test'
// }
// }
// }
```

### Filters

```js
bodybuilder().filter([arguments])
```

Creates a filtered query using filter of type `filterType`.

#### Arguments

The specific arguments depend on the type of filter, but typically follow this
pattern:

* `filterType` - The name of the query, such as `'regexp'` or `'exists'`.
* `fieldToQuery` - The name of the field in your index to filter on.
* `searchTerm` - The string to search for.

```js
bodybuilder().filter('term', 'message', 'test').build()
// body == {
// query: {
// bool: {
// filter: {
// term: {
// message: 'test'
// }
// }
// }
// }
// }
```

### Aggregations

```js
bodybuilder().aggregation([arguments])
```

Creates an aggregation of type `aggregationType`.

#### Arguments

The specific arguments depend on the type of aggregation, but typically follow
this pattern:

* `aggregationType` - The name of the aggregation, such as `'sum'` or `'terms'`.
* `fieldToAggregate` - The name of the field in your index to aggregate over.
* `aggregationName` - (optional) A custom name for the aggregation. Defaults to
`agg__`.
* `aggregationOptions` - (optional) Additional key-value pairs to include in the
aggregation object.
* `nestingFunction` - (optional) A function used to define aggregations as
children of the one being created. This _must_ be the last parameter set.

```js
var body = bodybuilder().aggregation('terms', 'user').build()
// body == {
// aggregations: {
// agg_terms_user: {
// terms: {
// field: 'user'
// }
// }
// }
// }
```

#### Nested aggregations

To nest aggregations, pass a `function` as the last parameter in `[arguments]`.
The `function` receives the recently built aggregation instance and is expected
to return an `Object` which will be assigned to `.aggs` on the current
aggregation. Aggregations in this scope behave like builders and you can call
the chainable method `.aggregation([arguments])` on them just as you would on
the main `bodybuilder`.

```js
var body = bodybuilder().aggregation('terms', 'code', {
order: { _term: 'desc' },
size: 1
}, agg => agg.aggregation('terms', 'name')).build()
// body == {
// "aggregations": {
// "agg_terms_code": {
// "terms": {
// "field": "code",
// "order": {
// "_term": "desc"
// },
// "size": 1
// },
// "aggs": {
// "agg_terms_name": {
// "terms": {
// "field": "name"
// }
// }
// }
// }
// }
//}
```

### Suggestions

```js
bodybuilder().suggest([arguments])
```

Creates a `phrase` or `term` suggestion.

#### Arguments

The specific arguments depend on the type of aggregation, but typically follow
this pattern:

* `suggestionType` - This can be either `phrase` or `term`.
* `fieldToAggregate` - The name of the field in your index to suggest on.
* `options` - An object of fields to include in the suggestions.
* `text` - The query to run on our suggest field.
* `name` - A custom name for the suggest clause.
* `analyzer` - The name of an analyzer to run on a suggestion.
* ... other suggest specific options, see [typings]('./bodybuilder.d.ts') or the [ElasticSearch suggest docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html) for more info

```js
var body = bodybuilder().suggest('term', 'user', { text: 'kimchy', 'name': 'user_suggest'}).build()
// body == {
// aggregations: {
// user_suggest: {
// text: 'kimchy',
// term: {
// field: 'user'
// }
// }
// }
// }
```

### Combining queries, filters, aggregations, and suggestions

Multiple queries and filters are merged using the boolean query or filter (see
[Combining Filters](https://www.elastic.co/guide/en/elasticsearch/guide/current/combining-filters.html)).

```js
var body = bodybuilder()
.query('match', 'message', 'this is a test')
.filter('term', 'user', 'kimchy')
.filter('term', 'user', 'herald')
.orFilter('term', 'user', 'johnny')
.notFilter('term', 'user', 'cassie')
.aggregation('terms', 'user')
.suggest('term', 'user', { text: 'kimchy' })
.build()

// body == {
// query: {
// bool: {
// must: {
// match: {
// message: 'this is a test'
// }
// },
// filter: {
// bool: {
// must: [
// {term: {user: 'kimchy'}},
// {term: {user: 'herald'}}
// ],
// should: [
// {term: {user: 'johnny'}}
// ],
// must_not: [
// {term: {user: 'cassie'}}
// ]
// }
// }
// },
// },
// aggs: {
// agg_terms_user: {
// terms: {
// field: 'user'
// }
// }
// }
// suggest_term_user: {
// text: 'kimchy',
// term: {
// field: 'user'
// }
// }
// }
```

#### Nesting Filters and Queries

It is even possible to nest filters, e.g. when some should and must filters have to be combined.

```js
var body = bodybuilder()
.orFilter('term', 'author', 'kimchy')
.orFilter('bool', b => b
.filter('match', 'message', 'this is a test')
.filter('term', 'type', 'comment')
)
.build()

// body == {
// query: {
// bool: {
// filter: {
// bool: {
// should: [
// { term: { author: 'kimchy' } },
// { bool: { must: [
// { match: { message: 'this is a test' } },
// { term: { type: 'comment' } }
// ] } }
// ]
// }
// }
// }
// }
// }
```

### Sort

Set a sort direction using `sort(field, direction)`, where direction defaults to
ascending.

```js
var body = bodybuilder()
.filter('term', 'message', 'test')
.sort('timestamp', 'desc')
.sort([{
"channel": {
"order": "desc"
}
}])
.sort([
{"categories": "desc"},
{"content": "asc"}
])
.build()

// body == {
// sort: [{
// "timestamp": {
// "order": "desc"
// }
// },
// {
// "channel": {
// "order": "desc"
// }
// },
// {
// "categories": {
// "order": "desc"
// }
// },
// {
// "content": {
// "order": "asc"
// }
// }
// ],
// query: {
// bool: {
// filter: {
// term: {
// message: 'test'
// }
// }
// }
// }
// }
```
**Advanced usage:** Set a sort configuration object for the given sort field with additional [sort properties](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html).
`sort(field, { sort: 'asc', mode: 'min', ...})`

### From / Size

Set `from` and `size` parameters to configure the offset and maximum hits to be
returned.

```js
var body = bodybuilder()
.filter('term', 'message', 'test')
.size(5)
.from(10)
.build()

// body == {
// size: 5,
// from: 10,
// query: {
// bool: {
// filter: {
// term: {
// message: 'test'
// }
// }
// }
// }
// }
```

### Other Options

Set any other search request option using `rawOption` passing in the key-value
pair to include in the body.

```js
var body = bodybuilder()
.filter('term', 'message', 'test')
.rawOption('_sourceExclude', 'verybigfield')
.build()

// body == {
// _sourceExclude: 'verybigfield',
// query: {
// bool: {
// filter: {
// term: {
// message: 'test'
// }
// }
// }
// }
// }
```

## Test

Run unit tests:

npm test

## Contributors

Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):

| [
Daniel Paz-Soldan](http://danpaz.me/)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=danpaz "Code") [πŸ“–](https://github.com/danpaz/bodybuilder/commits?author=danpaz "Documentation") [πŸš‡](#infra-danpaz "Infrastructure (Hosting, Build-Tools, etc)") [πŸ€”](#ideas-danpaz "Ideas, Planning, & Feedback") | [
NicolΓ‘s Fantone](https://github.com/nfantone)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=nfantone "Code") [⚠️](https://github.com/danpaz/bodybuilder/commits?author=nfantone "Tests") | [
Nauval Atmaja](http://nauvalatmaja.com)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=npatmaja "Code") | [
Ferron H](https://ferronrsmith.github.io/)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=ferronrsmith "Code") [⚠️](https://github.com/danpaz/bodybuilder/commits?author=ferronrsmith "Tests") [πŸ›](https://github.com/danpaz/bodybuilder/issues?q=author%3Aferronrsmith "Bug reports") [πŸ“–](https://github.com/danpaz/bodybuilder/commits?author=ferronrsmith "Documentation") | [
Dave Cranwell](http://davecranwell.com)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=davecranwell "Code") | [
Johannes Scharlach](https://github.com/johannes-scharlach)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=johannes-scharlach "Code") [πŸ“–](https://github.com/danpaz/bodybuilder/commits?author=johannes-scharlach "Documentation") [πŸ€”](#ideas-johannes-scharlach "Ideas, Planning, & Feedback") | [
Anton Samper Rivaya](https://rivaya.com)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=antonsamper "Code") [πŸ“–](https://github.com/danpaz/bodybuilder/commits?author=antonsamper "Documentation") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [
Suhas Karanth](https://github.com/sudo-suhas)
[πŸ’¬](#question-sudo-suhas "Answering Questions") | [
Jacob Gillespie](https://github.com/jacobwgillespie)
[πŸ’»](https://github.com/danpaz/bodybuilder/commits?author=jacobwgillespie "Code") |

This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!