npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

elastica

v2.1.0

Published

A flexible chaining API for ElasticSearch

Downloads

19

Readme

Elastica Build Status

A flexible chaining API for ElasticSearch

Raison D'être

Elasticsearch is an amazing tool. However, we find that it's hard to maintain a clean service layer to handle your ES requests. This library aims to make it easier to send requests and marshall responses from ES. The current version focuses on querying and marshaling aggregations. We'd like to add more features as we or the community needs them.

Contents

Request

Response

Installation

npm install elastica

Usage

Initialization

Initialize Elastica with the config you'd typically use in the ES Javascript API.

var elastica = require('elastica')(config.es)

Requests

Elastica uses a chained interface to simplify the creation of requests. Every function call returns a new request object. These objects are immutable, and can be saved and reused for convienience. Subsequent method calls will not change their state.

Used to make search queries. All search callbacks pass an Elastica Response Object.

Examples

Simple Search

The simple search uses for to describe the document type and in to describe the index range the search takes place in.

var query = '{"filter": { "term": { "field": "searchValue"} } }'

elastica.search
  .for('myDocType')
  .in('myIndex1,myIndex2')
  .exec(query, function(err, response) {
  })

Search With Compile

Compiled templates use erb syntax to build the search query.

var template = '{"filter": { "term": { "field": "<%= myField %>"} } }'

elastica.search
  .for('myDocType')
  .in('myIndex1,myIndex2')
  .compile(template)
  .exec({myField: 'searchValue'},function(err, response) {
  })

Request Reuse

var template = '{"filter": { "term": { "field": "<%= myField %>"} } }'

var search = elastica.search.for('myDocType').compile(template)
  
search.in('myIndex1').exec({myField: 'searchValue1'},function(err, response) {})
search.in('myIndex2').exec({myField: 'searchValue2'},function(err, response) {})

Search Options

Search takes an optional parameter that is passed to ES API, in order to qualify the search. In the following example we pass search_type and ignore_unavailable optional parameters to Elasticsearch.

var template = '{"filter": { "term": { "field": "<%= myField %>"} } }'

elastica.search
  .for('myDocType')
  .in('myIndex1,myIndex2')
  .compile(template)
  .exec({myField: 'searchValue'}, { 
    search_type: 'count', 
    ignore_unavailable: true
  }, function(err, response) {
  })

Update works very much like search with three additional operations: doc, with, and withScript. Update's callback returns the raw elasticsearch reponse.

Examples

Document Update

elastica.update
  .for('myDocType')
  .in('myIndex1')
  .doc('documentId')
  .with({updateField: 'updateValue'})
  .exec(function(err, response) {})

Script Update

elastica.update
  .for('myDocType')
  .in('myIndex1')
  .doc('documentId')
  .withScript('scriptNameOrContents', {scriptParam1: 'scriptValue1'})
  .exec(function(err, response) {})

Index's callback returns the raw elasticsearch reponse.

Examples

Document Update

elastica.index
  .for('myDocType')
  .in('myIndex1')
  .doc({field: 'value')
  .id(docId) //optional
  .parent(parentId) //optional
  .exec(function(err, response) {})

Bulk's only operation is add, which takes Elastica operations. Currently, only update operations are supported. Its callback also returns the raw elasticsearch response.

Examples
var update = elastica.update.for('myDocType').in('myIndex1')
elastica.bulk
  .add(update.doc('document1').with({update: 'value1'}))
  .add(update.doc('document2').with({update: 'value2'}))
  .exec(function(err, response) {})

// *Add* can also take an array of operations.
// The code below is equivalent to the code above.

elastica.bulk
  .add([
    update.doc('document1').with({update: 'value1'}), 
    update.doc('document2').with({update: 'value2'})
  ]).exec(function(err, response) {})

Responses

The Elastica response object exists primarily to marshall relevant values from the elastic search response. It has the following properties:

A field containing the raw response from elasticsearch.

elastica.search.exec(query, function(err, res) {
  console.dir(res.raw) // This will print the unmodified response body.
})

A function that returns the array of documents retrieved.

elastica.search.exec(query, function(err, res) {
  console.dir(res.hits()) // This will print the documents returned.
})

Aggs

Aggs is an object that provides functions to pull relevant data from the aggregations portion of the Elasticsearch response. There are four types of Elastica aggregations which map to ES aggregations.

Value aggregations map to the avg, sum, max, and min elasticsearch aggregations. The return value will be a key/value pair where the key is the aggregation name and the value is the aggregation value.

// Elasticsearch response is: 
// { aggregations: { totalSales: { value: 400 } } }

res.aggs.sum('totalSales') //Returns { totalSales: 400 }

Multi value aggregations map to the percentiles elasticsearch aggregation.

// Elasticsearch response is: 
// { aggregations: { salesPercentages: { values: { 25: 100, 50: 350, 75: 450 } } } }

res.aggs.percentiles('salesPercentages')
// Returns { salesPercentages: { 25: 100, 50: 350, 75: 450 } }

res.aggs.percentiles('salesPercentages', {asArray: true})
// Returns
// { 
//   salesPercentages: [
//     {key: 25, value: 100}, 
//     {key: 50, value: 350}, 
//     {key: 75, value: 450}
//   ] 
// }

Count aggregations map to the nested and filtered elasticsearch aggregations.

// Elasticsearch response is: 
// { aggregations: { highValuedSales: { doc_count: 500 } }

res.aggs.filter('highValuedSales')
// Returns { highValuedSales: { count: 500 } }

Count aggregations map to the ranges, terms, histogram, and geohashGrid elasticsearch aggregations.

// Elasticsearch response is: 
// { 
//   aggregations: { 
//     name: { buckets: [{key: 'Alice', doc_count: 100}, {key: 'Bob', doc_count: 200}] 
//   } 
// }

res.aggs.terms('name')
// Returns [{name: 'Alice', count: 100}, {name: 'Bob', count: 200}]

aggs.terms('artists', {with: 'range[transactions.revenue sales]'}

Dot notation

If you have deeply nested single count aggregations, you can use dot notation to access deeply nested child values.

// Elasticsearch response is: 
// { 
//   aggregations: { 
//     successfulTransactions: { 
//       doc_count: 500,  highValued:  { doc_count: 100, grossRevenue: {value: 1000000 } } 
//     } 
//   } 
// }

res.aggs.sum('successfulTransactions.highValued.grossRevenue')
// Returns { grossRevenue: 10000000 }

Aggregations can also be built from an aggregation expression. This allows quick and easy access for multiple aggregations at different levels of the response body. An expression can also be passed into Count and Multicount aggs as the with option in the second parameter.

Subaggregation expressions follow the EBNF grammar below:

expression = {subagg}

subagg = [type:]name[buckets]

buckets = "["{subagg}"]"

// Elasticsearch response is: 
// aggregations: {                                                                                                  
//   name: {                                                                                                        
//     buckets: [                                                                                                   
//       {                                                                                                          
//         key: "Alice",                                                                                            
//         doc_count: 300,                                                                                        
//         conversionRate: { value: 0.56 },                                                                         
//         transactions: {                                                                                          
//           doc_count: 200,                                                                                        
//           highValued: { value: 68 }
//         }                                                                                                        
//       },                                                                                                         
//       {                                                                                                          
//         key: "Bob",                                                                                              
//         doc_count: 200,                                                                                          
//         conversionRate: { value: 0.78 },                                                                         
//         transactions: {                                                                                          
//           doc_count: 350,                                                                                        
//           highValued: { value: 42 }
//         }                                                                                                        
//       }                                                                                                          
//     ]                                                                                                            
//   }                                                                                                              
// }

res.aggs.fromExpression('name[nested:transactions conversionRate transactions.highValued]')
// Returns
// { 
//   names: [
//     {name: "Alice", total: 300, conversionRate: 0.56, highValued: 68, transactions: {total: 200}},
//     {name: "Bob", total: 200, conversionRate: 0.78, highValued: 42, transactions: {total: 350}}
//   ]
// }

res.aggs.multiCount('name', {with: 'nested:transactions conversionRate transactions.highValued'})
// Returns [
//  {name: "Alice", total: 300, conversionRate: 0.56, highValued: 68, transactions: {total: 200}},
//  {name: "Bob", total: 200, conversionRate: 0.78, highValued: 42, transactions: {total: 350}}
// ]

What's next?

  • Interface for building queries.
  • Support for add operations
  • Support for delete operations