Greetings, dear readers of Habrahabr. I want to share with you my experience of using
backbone.js under
node.js. Earlier, I actively worked with backbone.js on the client, and this library turned out to be extremely convenient for structuring code.
A service without working with any database is not a service. In my case,
mongodb was chosen as the DBMS. I looked at the existing ORM solutions for mongodb, and it seemed to me more convenient to use familiar tools, the more they will be used on the client, so it was decided to try using the Backbone.Model class for the models and check how all this can be customized for mongodb.
So, the task. There is a certain service using the mongodb base. It is necessary to be able to create new objects and save them to the database, to get the necessary objects from a certain collection. After changing the object, it should be possible to save and delete it from the database.
')
Backbone.js provides us with 2 basic objects - a model and a collection. We will write a layer from which we will further inherit all of our future classes. At once I will make a reservation that we will set aside the code for connecting to the database and receiving the collection, and we will assume that everything is fine with it. Also neglect error handling. Almost everywhere I use Deferred. Therefore, who do not know what kind of beast, you can read about him
here in detail. Requests to mongodb are made through
this node.js module - which is not at all important. The code is simplified in some places, so if you use it in your project, something may not be entirely true.
Basic model
We need to somehow get a single model from the base, I think this method fits well with the static part of the class:
var BaseModel = Backbone.Model.extend({ idAttribute: "_id", },{ db_collection: null,
The code also shows that we have redefined the base field of the Backbone.Model class, which defines the name of the key field in the list of object fields, and in the static db_collection field of the class we defined the collection to which the object will belong.
After that, if we, for example, define a user class:
var User = BaseModel.extend({},{ db_collection:"users"});
we can get a specific user, like this:
User.fetchFromDb({_id:1});
Now you need to learn how to save the created model. To do this, backbone.js provides a special sync method, the signature of which looks like this:
function sync(method, model, options)
Where:
- method - the save method, depending on the situation may be returned:
- create - create a new model in the database;
- update - save the data of the existing model in the database;
- read - update the existing model from the database;
- delete - delete an object from the database.
- model is our object to save;
- options is what we passed with additional parameters at the moment of saving.
sync: function(method, model, options){ var fltr = {}; var deferred = new Deferred(); db.getCollection(this.constructor.db_collection, collectionReady.bind(this)); return deferred.promise; function collectionReady(err, collection){ function done(err, result){ if (options.success) options.success(result);
Here, too, nothing complicated. For each specific method of changing the model, we hang handlers who can do this action in the database itself.
Now, after creating the user object, for example, like this:
var user = new User({name:"Danil"});
we can safely keep it:
user.save()
and also delete after saving:
user.delete()
Basic collection
Working with single models is quite boring, so we implement collections, however, the more basic class in backbone.js is for that. By analogy with the model, we will redefine the base class of the collection. All our future collections will be inherited from it. First, let's write the extraction of the list of “raw data” from the database:
var BaseCollection = Backbone.Collection.extend({ },{ db_collection: null, __fetchCollection:function(filter, collection){ var deferred = new Deferred(); function collectionReady(err, collection){ collection.find(filter).toArray(function(err, items) { deferred.resolve(items); }.bind(this)); } db.getCollection(collection_db, collectionReady, this); return deferred.promise; } });
Here we create a static class method that will allow us to retrieve the list of “raw data” from the database, and also add a static db_collection field, which the heirs will override, indicating which collection in mongodb this class belongs to.
It remains to add the initialization of the necessary models, add another static method to our base collection class:
fetchFromDb:function(filter){ var deferred = new Deferred(); this.__fetchCollection(filter, this.db_collection).then( function(models){ deferred.resolve(new this(models)); }.bind(this) ); return deferred.promise; },
Here we just get the “raw data” and initialize the models associated with this collection with data from the database. Of course, the very name of the collection in mongodb we can get from the associated model, but we will consider it a simplification.
Now, having defined a collection of users, we can make requests to the database, receiving objects with users:
var Users = BaseCollection.extend({model:User}, {db_collection: "users"}); Users.fetchFromDb({name:"Danil"}).then(function(users){ _.each(users,function(user){console.log(user.id)}); });
As a result, we got all the necessary minimum for working with mongodb and we can continue to use other opportunities that backbone.js gives us.