Provides easy access to couchbase and elasticsearch from Sails.js & Waterline.
This module is a Waterline/Sails adapter. Its goal is to provide a set of declarative interfaces, conventions, and best-practices for integrating with all sorts of data sources. Not just databases-- external APIs, proprietary web services, or even hardware.
To install this adapter, run:
$ npm install sails-cbes
- Auto create Elasticsearch index
- ElasticSearch mapping is auto imported if it is defined in the model.
- To update Elasticsearch mapping you need to delete the index
- For each model a couchbase view will be created. The views are used for getting entire collection
Model with elastic search mapping example:
module.exports = {
identity: 'user',
tableName: 'userTable',
connection: 'semantic',
attributes: {
firstName: 'string',
lastName: 'string',
email: {
type: 'string',
defaultsTo: '[email protected]'
},
avatar: 'binary',
title: 'string',
phone: 'string',
type: 'string',
favoriteFruit: {
defaultsTo: 'blueberry',
type: 'string'
},
age: 'integer', // integer field that's not auto-incrementable
dob: 'datetime',
status: {
type: 'boolean',
defaultsTo: false
},
percent: 'float',
list: 'array',
obj: 'json',
fullName: function () {
return this.firstName + ' ' + this.lastName;
}
},
mapping: {
"_all": {
"enabled": false
},
firstName: {
type: 'string',
analyzer: 'whitespace',
fields: {
raw: {
type: 'string',
index: 'not_analyzed'
}
}
},
lastName: {
type: 'string',
analyzer: 'whitespace'
},
email: {
type: 'string',
analyzer: 'standard'
},
avatar: {
type: 'binary'
},
title: {
type: 'string',
analyzer: 'whitespace',
},
phone: {
type: 'string',
analyzer: 'keyword'
},
type: {
type: 'string',
analyzer: 'keyword'
},
favoriteFruit: {
type: 'string',
analyzer: 'whitespace'
},
age: {
type: 'integer',
index: 'not_analyzed'
},
createdAt: {
type: 'date',
format: 'dateOptionalTime'
},
updatedAt: {
type: 'date',
format: 'dateOptionalTime'
},
status: {
type: 'boolean'
},
percent: {
type: 'float'
},
obj: {
type: 'object'
}
}
};
{
//couchbase
cb: {
host: 'localhost',
port: 8091,
user: 'user',
pass: 'password',
operationTimeout: 60 * 1000, // 60s
bucket: {
name: 'bucket',
pass: 'bucketPassword'
}
},
//elasticsearch
es: {
host: ['127.0.0.1:9200'],
log: 'error',
index: 'index',
numberOfShards: 5,
numberOfReplicas: 1
}
},
This adapter exposes the following methods:
- Status
- Done
This method accepts Elastic Search filtered query. Only send the filtered.filter part of the query!
var elasticsearchFilterQuery = {
bool: {
must: [
{
term: {
type: 'createEach'
}
},
{
terms: {
firstName: ['createEach_1', 'createEach_2']
}
}
]
}
};
Semantic.User.find()
.where(elasticsearchFilterQuery)
.skip(0)
.limit(10)
.sort({createdAt: 'desc'})
.exec(function(err, res){
// do something
});
If you dont set no query to the find() method, find() will use couchbase view and return the entire collection.
This is the generated Elastic Search query for the above example:
query: {
filtered: {
query: {
bool: {
must: [{
term: {
_type: {
value: modelType
}
}
}]
}
},
filter: {
bool: {
must: [
{
term: {
type: 'createEach'
}
},
{
terms: {
firstName: ['createEach_1', 'createEach_2']
}
}
]
}
}
},
size: 10,
from: 0,
sort: [
{
createdAt: {
order: 'desc'
}
}
]
}
- Status
- Done
This method accepts Elastic Search filtered query. Only send the filtered.filter part of the query!
var elasticsearchFilterQuery = {
bool: {
must: [
{
term: {
type: 'findOne'
}
}
]
}
};
Semantic.User.findOne(elasticsearchFilterQuery).exec(function(err, res){
// do something
});
- Status
- Done
Semantic.User.create({ firstName: 'createEach_1', type: 'createEach' }, function(err, res) {
// do something
})
- Status
- Done
var usersArray = [
{ firstName: 'createEach_1', type: 'createEach' },
{ firstName: 'createEach_2', type: 'createEach' }
];
Semantic.User.createEach(usersArray, function(err, res) {
// do something
})
- Status
- Done
This method accepts Elastic Search filtered query. Only send the filtered.filter part of the query!
Check find() method.
var elasticsearchFilterQuery = {
bool: {
must: [
{
term: {
type: 'update'
}
},
{
term: {
firstName: 'update_1'
}
}
]
}
};
Semantic.User.update(elasticsearchFilterQuery, {lastName: 'updated'}).exec(function(err, res){
// do something
});
- Status
- Done
This method accepts Elastic Search filtered query. Only send the filtered.filter part of the query!
Check find() method.
var elasticsearchFilterQuery = {
bool: {
must: [
{
term: {
type: 'getRawCollection'
}
}
]
}
};
Semantic.User.destroy(elasticsearchFilterQuery).limit(999999).exec(function(err, res){
// do something
});
- Status
- Done
This method returns raw data from Couchbase view.
Semantic.User.getRawCollection(function(err, res){
// do something
});
- Status
- Done
This method synchronizes couchbase and elasticsearch by dropping the mapping (along with the entries) from elasticsearch and reimporting them from couchbase.
Semantic.User.reindex(function(err){
// do something
});
In order to use the document expiration functionality, the model should contain an additional attribute, "_ttl", as in the following example:
module.exports = {
connection: 'sailsCbes',
attributes: {
foo: {
type: 'string',
defaultsTo: 'bar'
},
_ttl: {
type: 'int',
defaultsTo: 1000 * 60 * 10 // 10 min
}
}
mapping:{
foo : {
type : 'string',
analyzer : 'standard',
index : 'analyzed'
}
}
};
The default value for ttl must be specified like in the above example. A value of 0 means that by default the document does not expire.
Then the expiration timer can be specified for each document as follows:
var data = {
foo : 'newBar',
_ttl : 1000 * 180
};
waterlineModel.create(data).exec(callback);
Check out Connections in the Sails docs, or see the config/connections.js
file in a new Sails project for information on setting up adapters.
In your adapter's directory, run:
$ npm test
- Stackoverflow
- #sailsjs on Freenode (IRC channel)
- Professional/enterprise
- Tutorials
© 2015 Kreditech / aronluigi & [contributors] Mohammad Bagheri, Robert Savu, Tiago Amorim & contributors
Sails is free and open-source under the MIT License