Home

node-cassandra Build Status Coverage Status

Cassandra ORM for NodeJS, based on the cassandra-driver module.

Read the full API Documentation.

Examples:

Cassandra Known Versions Supported:

  • 3.x

Known Supported NodeJS Versions:

  • <= 7.6
  • 6.x
  • 5.x

Getting Started

Connecting to the database

var Cassandra = require('node-cassandra');
var config = {
    contactPoints: ['127.0.0.1:9042'],
    protocolOptions: {port: 9042},
    keyspace: {
        testkeyspace: {
            durableWrites: true,
            withReplication: {
                class: 'SimpleStrategy',
                replication_factor: 1
            }
        }
    }
};

var cassandra = Cassandra.connect(config);
cassandra.on('error', (err) => console.log(err));
cassandra.on('connect', (err) => console.log('connected'));

Creating your first Schema, Model and Materialized View

//create a new schema
var schema = new Cassandra.Schema({
    id: {
        type: 'uuid',
        default: Cassandra.uuid
    },
    username: {
        type: 'text',
        required: true
    },
    ageName: {
        type: 'text',
        default: (instance) => { 
            //default value functions are passed the object instance
            return instance.age + instance.name;
        }
    },
    name: 'text',
    age: 'int'
}, {
    primaryKeys: ['username'],
    views: {
        byName: {
            primaryKeys: ['name'],
            orderBy: {
                name: 'asc'
            }
        },
    }
});

//create model
var TestModel = cassandra.model('testModel', schema, (err) => {
    test.save((err) => {
        if (err) {
            throw err;
        }
        console.log('test saved!');
        test.age = 29;
        test.save((err) => {...});
        //test.age updated
    });
});

var test = new TestModel({
    name: 'bar',
    username: 'foo',
    age: 30
});

Working with Collections and Indexes

List Types

//create a new schema
var schema = new Cassandra.Schema({
    name: 'text',
    usernames: {
        type: {
            list: 'text'
        }
    }
}, {
    indexes: ['usernames'], //create an index on the usernames column
    primaryKeys: ['name']
});

Inserting lists

//create model
var TestModel = cassandra.model('testModel', schema, (err) => {
    var test = new TestModel({
        name: 'bar',
        usernames: ['foo', 'bar']
    });
    test.save(() => {
        TestModel.findOne({
            usernames: {
                $contains: 'foo'
            }
        }, (err, row) => {
            console.log(row.usernames); //['foo', 'bar']
        });
    });
});

Updating lists

//following above
var query = {
    name: 'bar',
    usernames: {
        $contains: 'foo'
    }
};
var updateObject = {
    usernames: {
        $filter: ['foo'], //remove items matching "foo"
        $append: ['baz'], //append item "baz"
        $prepend: ['fii'] //prepend item "fii"
    }
};
TestModel.update(query, updateObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne({usernames: {$contains: 'baz'}}, (err, row) => {
        console.log(row.usernames); //['fii', 'bar', 'baz']
    });
});

Updating lists by index

//following above
var query = {
    name: 'bar',
    usernames: {
        $contains: 'bar'
    }
};
var updateObject = {
    usernames: {
        $set: {
            0: 'foo'
        }
    }
};
TestModel.update(query, updateObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne(query, (err, row) => {
        console.log(row.usernames); //['foo', 'bar', 'baz']
    });
});

Deleting lists by column or index

//following above
var query = {
    name: 'bar',
    usernames: {
        $contains: 'fii'
    }
};
var deleteObject = {
    usernames: [0,2] //delete first and last index
};
TestModel.delete(query, deleteObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne({usernames: {$contains: 'bar'}}, (err, row) => {

        console.log(row.usernames); //['bar']

        TestModel.delete({
            usernames: {
                $contains: 'bar'
            }
        }, {
            usernames: 1 //delete usernames column
        }, (err) => {...});

    });
});

Set Types

//create a new schema
var schema = new Cassandra.Schema({
    name: 'text',
    usernames: {
        type: {
            set: 'text'
        }
    }
}, {
    indexes: ['usernames'], //create an index on the usernames column
    primaryKeys: ['name']
});

Inserting sets

//create model
var TestModel = cassandra.model('testModel', schema, (err) => {
    var test = new TestModel({
        name: 'bar',
        usernames: ['foo', 'bar']
    });
    test.save(() => {
        TestModel.findOne({
            usernames: {
                $contains: 'foo'
            }
        }, (err, row) => {
            console.log(row.usernames); //['bar', 'foo']
        });
    });
});

Updating sets

//following above
var query = {
    name: 'bar',
    usernames: {
        $contains: 'bar'
    }
};
var updateObject = {
    usernames: {
        $add: ['aba', 'boa'],
        $filter: ['foo']
    }
};
TestModel.update(query, updateObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne(query, (err, row) => {
        console.log(row.usernames); //['aba', 'bar', 'boa']
    });
});

Update sets to null

//following above
var query = {
    name: 'bar',
    usernames: {
        $contains: 'bar'
    }
};
var updateObject = {
    usernames: [] //or null
};
TestModel.update(query, updateObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne(query, (err, row) => {
        console.log(row.usernames); //null
    });
});

Deleting sets

//not much you can do with deleting sets
var query = {
    name: 'bar',
    usernames: {
        $contains: 'fii'
    }
};
var deleteObject = {
    usernames: 1 //delete usernames column
};
TestModel.delete(query, deleteObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne({name: 'bar'}, (err, row) => {
        console.log(row.usernames); //null
    });
});

Map Types

//create a new schema
var schema = new Cassandra.Schema({
    name: 'text',
    usernames: {
        type: {
            map: ['text', 'int']
        }
    }
}, {
    indexes: ['usernames'], //create an index on the usernames column keys
    primaryKeys: ['name']
});

Inserting maps

//create model
var TestModel = cassandra.model('testModel', schema, (err) => {
    var test = new TestModel({
        name: 'bar',
        usernames: {
            $set: {
                foo: 2,
                bar: 4
            }
        }
    });
    test.save(() => {
        TestModel.findOne({
            usernames: {
                $containsKey: 'foo' //use containsKey for maps
            }
        }, (err, row) => {
            console.log(row.usernames.foo); // 2
        });
    });
});

Updating maps

//following above
var query = {
    name: 'bar',
    usernames: {
        $containsKey: 'bar'
    }
};
var updateObject = {
    usernames: {
        foo: 5, //update "foo" to 5
        fii: 7 /set "fii" to 7
    }
};
TestModel.update(query, updateObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne(query, (err, row) => {
        console.log(row.usernames.foo); // 5
    });
});

Deleting maps by Keys

//not much you can do with deleting maps
var query = {
    name: 'bar',
    usernames: {
        $containsKey: 'bar'
    }
};
var deleteObject = {
    usernames: ['foo']
};
TestModel.delete(query, deleteObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne(query, (err, row) => {
        console.log(row.usernames.foo); // undefined
    });
});

Deleting maps

//not much you can do with deleting maps
var query = {
    name: 'bar',
    usernames: {
        $containsKey: 'bar'
    }
};
var deleteObject = {
    usernames: 1
};
TestModel.delete(query, deleteObject, (err) => {
    if (err) {
        return console.log(err):
    }
    TestModel.findOne(query, (err, row) => {
        console.log(row.usernames); // null
    });
});

Table Compaction

//create a new schema
var schema = new Cassandra.Schema({
    id: 'uuid',
    name: 'text'
}, {
    primaryKeys: ['username'],
    compaction: {
        class: 'DateTieredCompactionStrategy', 
        timestamp_resolution: 'MICROSECONDS',
        base_time_seconds: 3600, 
        max_sstable_age_days: 365
    }
});

Static Methods

//create a new schema
var schema = new Cassandra.Schema({
    id: {
        type: 'uuid',
        default: Cassandra.uuid
    },
    username: {
        type: 'text',
        required: true
    },
    name: 'text'
}, {
    primaryKeys: ['username'],
    views: {
        byName: {
            primaryKeys: ['name']
        },
    }
});

//attach static method - fat arrow functions won't work here as we need the context to change
schema.statics.findByName = function (name, callback) {
    this.views.byName.findOne({name: name}, callback);  
};

//create model
var TestModel = cassandra.model('testModel', schema, (err) => {
    TestModel.findByName('foo', (err, row) => {
        console.log(row.name); // "foo"
    });
});

Stress Utility

node-cassandra includes an interactive command line utility.

  • read - make n asynchronous read requests, with n iterations
  • write - make multiple write requests, creates fake user data
  • load - make n read requests per second (randomized timing), with n iterations
  • count - count how many rows you have created with the write command
  • clean - drop the keyspace and exit
  • help - display the help text below

running node ./stress --help

NODE-CASSANDRA STRESS UTILITY

  SYNOPSIS
      node ./stress [OPTIONS]

  OPTIONS
      --host           cassandra host address (default=127.0.0.1)
      --port           cassandra listen port (default=9042)
      --keyspace       cassandra table keyspace (default=loadtest)
      --cluster        run tests in cluster mode
      --nodes          number of nodes to spawn in cluster mode (default=numCPUs)
      --help           show this help
  • Setting "--cluster" will start the cli in cluster mode. By default, one node will fork for each CPU core. You can manually set the number of forks with "--nodes" option.
  • In cluster mode read, write, and load tests will be performed in parallel on each node. If you have 4 nodes running, then write 1000 rows, you will be writing 4000 rows to the database.