Category Archives: General

Backbone.Sync Demo

It’s been a while since I did my last coding post, but finally I have something on the oven :)

It is a demo of 3 different ways to use Backbone.Sync with your server. I’ve seen mostly 3 different ways to create services, based on the technology, framework or the developer expertise:

  • 1 URL for each operation
  • 1 URL for all operations (gateway) and different actions inside it
  • RESTful

As soon as I am done with the documentation I’ll update it here (this same post), but if you can’t wait to read it you can always go and see the code :)

 

Mongoose – Models with Circular References

Today at the office I realized of an interesting use case on MongoDB and Mongoose: Many to Many relationship. I had no idea if Mongoose was going to fall in an infinite loop trying to populate each nested document but turns that it populates only the child documents (first level) 8)

On a standard SQL DataBase this kind of relationship is easy to accomplish by using a table to store the ids of the items you want to be related but if you are on a NoSQL DataBase and you want to achieve the same result… well, it is not exactly the same way, but it is not hard either. Let’s see an example.

Let’s say you have two collections: Posts and Attachments. Usually you may be able to Add many attachments to a post, or maybe you want to share a file to many posts, but since we want to do something more interesting we are going to support both: Attach multiple files to a post but also allow your attachments to be shared on multiple posts :D

A common way to handle documents related on a NoSQL DB is to create sub-documents  this allows you to do a one-to-many relation but since we want a many-to-many then what we will do is to use the nice “Populate” method available on Mongoose and save ID references as an array, either attachments IDs on a Post, post IDs on an Attachment or even both!

You can see the code below and an example output, or if you prefer you can also download or fork it on GitHub.

// Dependencies
var mongoose = require('mongoose'),
	async = require('async');

// Connect to Mongoose
mongoose.connect('mongodb://localhost:27017/circular');

var Schema = mongoose.Schema,
	ObjectId = Schema.Types.ObjectId;

// Schema definitions
var PostSchema = new Schema({
	title: {
		type: String,
		'default': ''
	},
	content: {
		type: String,
		'default': ''
	}
});
var AttachmentSchema = new Schema({
	fileName: {
		type: String,
		'default': ''
	}
});

// Circular reference definitions
PostSchema.add({
	attachments: [{
		type: ObjectId,
		ref: 'Attachment'
	}]
});
AttachmentSchema.add({
	posts: [{
		type: ObjectId,
		ref: 'Post'
	}]
});

// A couple of methods to save references inside the documents by using only
// the _id instead of creating a subdocument.
PostSchema.methods.attach = function(attachment, callback) {
	var post = this;
	this.attachments.push(attachment);
	this.save(function(err) {
		attachment.posts.push(post);
		attachment.save(callback);
	});
};
AttachmentSchema.methods.share = function(post, callback) {
	var attachment = this;
	this.posts.push(post);
	this.save(function(err) {
		post.attachments.push(attachment);
		post.save(callback);
	});
};

// Models definition
var Post = mongoose.model('Post', PostSchema, 'posts');
var Attachment = mongoose.model('Attachment', AttachmentSchema, 'attachments');

// Go parallel!
async.parallel({
	post: function(callback) {
		console.log('creating a post');
		var p = new Post({
			title: 'Test post (' + Date.now() + ')',
			content: 'Test post (' + Date.now() + ')'
		});
		p.save(callback);
	},
	attachment: function(callback) {
		console.log('creating an attachment');
		var a = new Attachment({
			fileName: 'test_' + Date.now() + '.txt'
		});
		a.save(callback);
	}
}, function(err, res) {
	// Once we have a new post and a new attachment, create a relation on each one,
	// this is only a demo of having the reference of each other but it is not required.
	res.post[0].attach(res.attachment[0], function(err, res) {
		// Dump the current data, just to see if it is working ;) 
		async.series([function(callback) {
			// Read all our posts and their attachments
			Post.find().populate('attachments').exec(function(err, posts) {
				if (err) {
					return callback(err);
				}

				posts.forEach(function(post) {
					console.log('Post ' + post.title + ' has ' + post.attachments.length + ' attachment(s):');
					post.attachments.forEach(function(attachment) {
						console.log('- Filename: ' + attachment.fileName);
					});
				});
				callback();
			});
		}, function(callback) {
			// Read all our attachments and their posts
			Attachment.find().populate('posts').exec(function(err, attachments) {
				if (err) {
					return callback(err);
				}
				attachments.forEach(function(attachment) {
					console.log('Attachment ' + attachment.fileName + ' is shared in ' + attachment.posts.length + ' post(s):');
					attachment.posts.forEach(function(post) {
						console.log('- Post: ' + post.title);
					});
				});
				callback();
			});
		}], function(err) {
			mongoose.disconnect();
		});
	});
});

After executing this file some times, I got an output like this one:

> node index.js
creating a post
creating an attachment
Post Test post (1354674892970) has 1 attachment(s):
- Filename: test_1354674892973.txt
Post Test post (1354674914843) has 1 attachment(s):
- Filename: test_1354674914845.txt
Attachment test_1354674892973.txt is shared in 1 post(s):
- Post: Test post (1354674892970)
Attachment test_1354674914845.txt is shared in 1 post(s):
- Post: Test post (1354674914843)

Grunt Task: Grunt String Replace

Many of the best projects I have seen and used started as a really simple idea whose objective was to solve one need. Some of the developers behind those decided to contribute their time and experience to the world by sharing their projects as Open Source and now, now it is my turn to contribute with a little one: grunt-string-replace.

I am in the process of improve some tools on my day to day moving away from Ant into Grunt and some of the tasks required to execute different string replacements across multiple files. I started by searching a grunt task but there was not a single one to accomplish what I needed at that time; I found some general replacement tools, or token replacements, but never the flexibility or the power to perform regular expression search and replaces. So, I decided it was my time to create a task to do so, and I did it.

 

grunt-string-replace 

Replaces strings on files by using string or regex patterns. Attempts to be a String.prototype.replace adapter task for your grunt project.

 

More details at the module page https://github.com/erickrdch/grunt-string-replace