NOTE: Oriento is deprecated, development continues at https://github.com/orientechnologies/orientjs
Official orientdb driver for node.js. Fast, lightweight, uses the binary protocol.
Oriento aims to work with version 1.7.1 of orientdb and later. While it may work with earlier versions, they are not currently supported, pull requests are welcome!
IMPORTANT: Oriento does not currently support OrientDB's Tree Based RIDBag feature because it relies on making additional network requests. This means that by default, the result of e.g.
JSON.stringify(record)
for a record with up to 119 edges will be very different from a record with 120+ edges. This can lead to very nasty surprises which may not manifest themselves during development but could appear at any time in production. There is an open issue for this in OrientDB, until that gets fixed, it is strongly recommended that you setRID_BAG_EMBEDDED_TO_SBTREEBONSAI_THRESHOLD
to a very large value, e.g. 2147483647. Please see the relevant section in the OrientDB manual for more information.
Install via npm.
npm install oriento
To run the test suite, first invoke the following command within the repo, installing the development dependencies:
npm install
Then run the tests:
npm test
- Tested with latest orientdb (1.7).
- Intuitive API, based on bluebird promises.
- Fast binary protocol parser.
- Access multiple databases via the same socket.
- Migration support.
- Simple CLI.
- Connection Pooling
var Oriento = require('oriento');
var server = Oriento({
host: 'localhost',
port: 2424,
username: 'root',
password: 'yourpassword'
});
server.list()
.then(function (dbs) {
console.log('There are ' + dbs.length + ' databases on the server.');
});
server.create({
name: 'mydb',
type: 'graph',
storage: 'plocal'
})
.then(function (db) {
console.log('Created a database called ' + db.name);
});
var db = server.use('mydb');
console.log('Using database: ' + db.name);
var db = server.use({
name: 'mydb',
username: 'admin',
password: 'admin'
});
console.log('Using database: ' + db.name);
db.query('insert into OUser (name, password, status) values (:name, :password, :status)',
{
params: {
name: 'Radu',
password: 'mypassword',
status: 'active'
}
}
).then(function (response){
console.log(response); //an Array of records inserted
});
db.query('select from OUser where name=:name', {
params: {
name: 'Radu'
},
limit: 1
}).then(function (results){
console.log(results);
});
db.exec('select from OUser where name=:name', {
params: {
name: 'Radu'
}
}).then(function (response){
console.log(response.results);
});
db.insert().into('OUser').set({name: 'demo', password: 'demo', status: 'ACTIVE'}).one()
.then(function (user) {
console.log('created', user);
});
db.update('OUser').set({password: 'changed'}).where({name: 'demo'}).scalar()
.then(function (total) {
console.log('updated', total, 'users');
});
db.delete().from('OUser').where({name: 'demo'}).limit(1).scalar()
.then(function (total) {
console.log('deleted', total, 'users');
});
db.select().from('OUser').where({status: 'ACTIVE'}).all()
.then(function (users) {
console.log('active users', users);
});
db.select().from('OUser').containsText({name: 'er'}).all()
.then(function (users) {
console.log('found users', users);
});
db.select().from('OUser').where({status: 'ACTIVE'}).fetch({role: 5}).all()
.then(function (users) {
console.log('active users', users);
});
db.select('count(*)').from('OUser').where({status: 'ACTIVE'}).scalar()
.then(function (total) {
console.log('total active users', total);
});
db.traverse().from('OUser').where({name: 'guest'}).all()
.then(function (records) {
console.log('found records', records);
});
db
.select('name')
.from('OUser')
.where({status: 'ACTIVE'})
.column('name')
.all()
.then(function (names) {
console.log('active user names', names.join(', '));
});
db
.select('name')
.from('OUser')
.where({status: 'ACTIVE'})
.transform({
status: function (status) {
return status.toLowerCase();
}
})
.limit(1)
.one()
.then(function (user) {
console.log('user status: ', user.status); // 'active'
});
db
.select('name')
.from('OUser')
.where({status: 'ACTIVE'})
.transform(function (record) {
return new User(record);
})
.limit(1)
.one()
.then(function (user) {
console.log('user is an instance of User?', (user instanceof User)); // true
});
db
.select('name')
.from('OUser')
.where({status: 'ACTIVE'})
.defaults({
something: 123
})
.limit(1)
.one()
.then(function (user) {
console.log(user.name, user.something);
});
db
.update('#1:1')
.put('mapProperty', {
key: 'value',
foo: 'bar'
})
.scalar()
.then(function (total) {
console.log('updated', total, 'records');
});
db.record.get('#1:1')
.then(function (record) {
console.log('Loaded record:', record);
});
db.record.delete('#1:1')
.then(function () {
console.log('Record deleted');
});
db.class.list()
.then(function (classes) {
console.log('There are ' + classes.length + ' classes in the db:', classes);
});
db.class.create('MyClass')
.then(function (MyClass) {
console.log('Created class: ' + MyClass.name);
});
db.class.create('MyOtherClass', 'MyClass')
.then(function (MyOtherClass) {
console.log('Created class: ' + MyOtherClass.name);
});
db.class.get('MyClass')
.then(function (MyClass) {
console.log('Got class: ' + MyClass.name);
});
db.class.update({
name: 'MyClass',
superClass: 'V'
})
.then(function (MyClass) {
console.log('Updated class: ' + MyClass.name + ' that extends ' + MyClass.superClass);
});
MyClass.property.list()
.then(function (properties) {
console.log('The class has the following properties:', properties);
});
MyClass.property.create({
name: 'name',
type: 'String'
})
.then(function () {
console.log('Property created.')
});
MyClass.property.drop('myprop')
.then(function () {
console.log('Property deleted.');
});
MyClass.property.rename('myprop', 'mypropchanged');
.then(function () {
console.log('Property renamed.');
});
MyClass.create({
name: 'John McFakerton',
email: '[email protected]'
})
.then(function (record) {
console.log('Created record: ', record);
});
MyClass.list()
.then(function (records) {
console.log('Found ' + records.length + ' records:', records);
});
db.index.create({
name: 'MyClass.myProp',
type: 'unique'
})
.then(function(index){
console.log('Created index: ', index);
});
db.index.get('MyClass.myProp')
.then(function (index) {
index.get('foo').then(console.log.bind(console));
});
db.create('VERTEX', 'V').one()
.then(function (vertex) {
console.log('created vertex', vertex);
});
db.create('VERTEX', 'V')
.set({
key: 'value',
foo: 'bar'
})
.one()
.then(function (vertex) {
console.log('created vertex', vertex);
});
db.delete('VERTEX')
.where('@rid = #12:12')
.one()
.then(function (count) {
console.log('deleted ' + count + ' vertices');
});
db.create('EDGE', 'E')
.from('#12:12')
.to('#12:13')
.one()
.then(function (edge) {
console.log('created edge:', edge);
});
db.create('EDGE', 'E')
.from('#12:12')
.to('#12:13')
.set({
key: 'value',
foo: 'bar'
})
.one()
.then(function (edge) {
console.log('created edge:', edge);
});
db.delete('EDGE', 'E')
.from('#12:12')
.to('#12:13')
.scalar()
.then(function (count) {
console.log('deleted ' + count + ' edges');
});
You can create a function by supplying a plain javascript function. Please note that the method stringifies the function
passed so you can't use any varaibles outside the function closure.
db.createFn("nameOfFunction", function(arg1, arg2) {
return arg1 + arg2;
})
.then(function (count) {
// Function created!
});
You can also omit the name and it'll default to the Function#name
db.createFn(function nameOfFunction(arg1, arg2) {
return arg1 + arg2;
})
.then(function (count) {
// Function created!
});
An extremely minimalist command line interface is provided to allow databases to created and migrations to be applied via the terminal.
To be useful, oriento requires some arguments to authenticate against the server. All operations require the password
argument unless the user is configured with an empty password. For operations that involve a specific db, include the dbname
argument (with dbuser
and dbpassword
if they are set to something other than the default).
You can get a list of the supported arguments using oriento --help
.
-d, --cwd The working directory to use.
-h, --host The server hostname or IP address.
-p, --port The server port.
-u, --user The server username.
-s, --password The server password.
-n, --dbname The name of the database to use.
-U, --dbuser The database username.
-P, --dbpassword The database password.
-?, --help Show the help screen.
If it's too tedious to type these options in every time, you can also create an oriento.opts
file containing them. Oriento will search for this file in the working directory and apply any arguments it contains.
For an example of such a file, see test/fixtures/oriento.opts.
Note: For brevity, all these examples assume you've installed oriento globally (
npm install -g oriento
) and have set up an oriento.opts file with your server and database credentials.
oriento db list
oriento db create mydb graph plocal
oriento db drop mydb
Oriento supports a simple database migration system. This makes it easy to keep track of changes to your orientdb database structure between multiple environments and distributed teams.
When you run a migration command, oriento first looks for an orient class called Migration
. If this class doesn't exist it will be created.
This class is used to keep track of the migrations that have been applied.
Oriento then looks for migrations that have not yet been applied in a folder called migrations
. Each migration consists of a simple node.js module which exports two methods - up()
and down()
. Each method receives the currently selected database instance as an argument.
The up()
method should perform the migration and the down()
method should undo it.
Note: Migrations can incur data loss! Make sure you back up your database before migrating up and down.
In addition to the command line options outlined below, it's also possible to use the migration API programatically:
var db = server.use('mydb');
var manager = new Oriento.Migration.Manager({
db: db,
dir: __dirname + '/migrations'
});
manager.up(1)
.then(function () {
console.log('migrated up by one!')
});
To list all the unapplied migrations:
oriento migrate list
oriento migrate create my new migration
creates a file called something like m20140318_200948_my_new_migration
which you should edit to specify the migration up and down methods.
To apply all the migrations:
oriento migrate up
To apply only the first migration:
oriento migrate up 1
To revert all migrations:
oriento migrate down
oriento migrate down 1
You can also bind to the following events
Given the query
db.select('name, status').from('OUser').where({"status": "active"}).limit(1).fetch({"role": 1}).one();
The following event will be triggered
db.on("beginQuery", function(obj) {
// => {
// query: 'SELECT name, status FROM OUser WHERE status = :paramstatus0 LIMIT 1',
// mode: 'a',
// fetchPlan: 'role:1',
// limit: -1,
// params: { params: { paramstatus0: 'active' } }
// }
});
After a query has been run, you'll get the the following event emitted
db.on("endQuery", function(obj) {
// => {
// "err": errObj,
// "result": resultObj,
// "perf": {
// "query": timeInMs
// }
// }
});
In 2012, Gabriel Petrovay created the original node-orientdb library, with a straightforward callback based API.
In early 2014, Giraldo Rosales made a whole host of improvements, including support for orientdb 1.7 and switched to a promise based API.
Later in 2014, codemix refactored the library to make it easier to extend and maintain, and introduced an API similar to nano. The result is so different from the original codebase that it warranted its own name and npm package. This also gave us the opportunity to switch to semantic versioning.
Please see CONTRIBUTING.
See CHANGELOG
Apache 2.0 License, see LICENSE