Schema Reference


module.exports = {
    fields: {
        id: {
            type: "uuid",
            default: {"$db_function": "uuid()"}
        },
        name: { type: "varchar", default: "no name provided"},
        surname: { type: "varchar", default: "no surname provided"},
        complete_name: {
            type: "varchar",
            default: function() {
                return this.name + ' ' + this.surname;
            }
        },
        password_hash: "blob",
        age: "int",
        active: "boolean",
        created: {
            type: "timestamp",
            default: {"$db_function": "toTimestamp(now())"}
        }
    },
    key : [["id"],"created"],
    clustering_order: {"created": "desc"},
    materialized_views: {
        view_name1: {
            select: ["name","age"],
            key : ["age","created","id"],
        },
        view_name2: {
            select: ["name","age","active"],
            key : [["name", "id"],"created"],
            clustering_order: {"created": "desc"}
        }
    },
    indexes: ["name"],
    custom_indexes: [
        {
            on: 'complete_name',
            using: 'org.apache.cassandra.index.sasi.SASIIndex',
            options: {}
        }
    ],
    table_name: "my_custom_table_name",
    methods: {
        setPassword: function (password, callback) {
          crypto.pbkdf2Sync('secret', 'salt', 100000, 512, 'sha512', (err, hashed) => {
            if (err) { return callback(err); }
            this.password_hash = hashed;
            return callback();
          });
        }
    }
}

What does the above code means?

  • fields are the columns of your table. For each column name the value can be a string representing the type or an object containing more specific informations. i.e.

    • "id" : { "type": "uuid", "default": {"$db_function": "uuid()"} }, in this example id type is uuid and the default value is a cassandra function (so it will be executed from the database).
    • "name" : { "type": "varchar", "default": "no name provided"}, in this case name is a varchar and, if no value will be provided, it will have a default value of no name provided. The same goes for surname.
    • complete_name the default values is calculated from others field. When the orm processes your model instances, the complete_name will be the result of the function you defined. In the function this is bound to the current model instance. If you need to use the custom datatypes, you may use the this._get_data_types() function that will be similar to using models.datatypes but the difference is, it can be used from within a model definition. For example to return a Long value from a default function, you could use the this._get_data_types().Long class.
    • age no default is provided and we could write it just as age: "int".
    • active no default is provided and we could write it just as active: "boolean".
    • created, like uuid(), will be evaluated from cassandra using the now() function.
  • key: here is where you define the primary key of your table. As you can imagine, the array defines a compound primary key and the first value of the array is the partition key and the others are the clustering keys. The partition key itself can be an array with multiple fields. When a partition key is an array of multiple fields, it is called a composite partition key.

    The partition key is the key field by which cassandra distributes it's data into multiple machines. So when querying cassandra, in most cases you need to provide the partition key, so cassandra knows which machines or partitions contains the data you are looking for.

    The clustering keys are used to keep the data sorted according to the field values of those keys in a partition. So that after getting into a partition, cassandra can find the required data under those partitions very quickly. As the data is sorted according to those keys, cassandra can efficiently seek to find the data it needs.

    Understanding the primary key parts is a crucial concept to cassandra data modeling. To get a detailed idea about them, read the cassandra documentation. For your convenience, following are some links to the relevant documentation pages:

    Read more about composite keys on the composite key doc

    Read more about the compound key here on the compound key documentation

  • clustering_order: here you can define the clustering order of the clustering keys. If order is not defined, default value of ASC (ascending) is used.

  • materialized_views provides you the ability to define cassandra 3.x materialized views for your model table. You may want to read more about it on the materialized view documentation. This is generally suited for querying high cardinality fields. If you need to use select * for the materialized view, you can also use select: ['*'].

  • indexes are the index of your table. It's always an array of field names. You can read more on the index documentation. This is generally suited for querying low cardinality fields, but not as low as boolean fields or fields with very limited number of variants. Very low cardinality fields are not a good separator of large datasets and hence not worthwhile to index.

  • custom_indexes is an array of objects defining the custom indexes for the table. The on section should contain the column name on which the index should be built, the using section should contain the custom indexer class path and the options section should contain the passed options for the indexer class if any. If no options are required, pass a blank {} object.

  • table_name provides the ability to use a different name for the actual table in cassandra. By default the lowercased modelname is used as the table name. But if you want a different table name instead, then you may want to use this optional field to specify the custom name for your cassandra table.

  • methods allows you to define custom methods for your instances. This can be useful when a single model method should act on various fields and therefore cannot be mapped to a virtual field, or when an asynchronous operation is required for reading or updating a field, such as hashing a password or retrieving related data against a database.

When you instantiate a model, every field you defined in schema is automatically a property of your instances. So, you can write:


john.age = 25;
console.log(john.name); //John
console.log(john.complete_name); // undefined.

note: john.complete_name is undefined in the newly created instance but will be populated when the instance is saved because it has a default value in schema definition

Ok, we are done with John, let's delete him:


john.delete(function(err){
    //...
});