This post is part of the series about creating an app with node.js, express for Facebook
For this part we will use the mongoose module that we already have installed, so no updates to the package.json.
Our model looks more or less to something like this:
Nomination is our main doc that have all the attributes to create a nomination, this one have a list of users, users its a doc that is embedded in nomination, i put it like this so you can see the separation but its not another doc in mongodb but we need to create the schema definition anyway in mongoose.
To add our modules lets create a folder called "models" or whatever in the root path of our app, inside that lets create a file called "nomination.js".
Lets see our code in nomination.js:
function defineModels(mongoose, fn) { var Schema = mongoose.Schema, Nomination, User; /** * * Model: User * */ User = new Schema({ '_id' : String, //fb id 'name' : String, //user name 'votes' : Number //number of votes for this user }); /** * * Model: Nomination * */ Nomination = new Schema({ 'name' : String, 'owner' : String, //who is the owner of the nomination 'endDate' : Date, //when this nomination is going to end 'users' : [User], //users added to this nomination 'voters' : [String], //all the dudes that vote this nomination 'category' : String, 'sub_cat' : String, 'active' : Boolean, //nomination finished 'erased' : [String] //people erased by facebook id, we wont be able to re-add them }); Nomination.virtual('id') .get(function() { return this._id.toHexString(); }); Nomination.pre('save', function(next) { //we could use this later next(); }); mongoose.model('Nomination', Nomination); fn(); } exports.defineModels = defineModels;
Line 1: Creating our main function to export later
2-3: our internal variables and a reference to schema
5-14: user model by "new Schema", with id gathered from fb, name and number of votes this user will have, all of type of String excepto votes
33-36: A virtual function to get the id, just in case
38-41: a small save middleware, before saving a doc of this type, mongoose will first call this function, for this example im not putting nothing yet, "next()" its to call the next function that in this case will be the actual save.
43: declaring the model
45: we call the callback passed, usually its to make an instance of the model to start using it
48: Exporting the function
Nice, we have our models defined, lets create something to use it, i called it "controller", from there we will handle the mongoose functionality so we are going to expose only whats is necesary.
We need to create a "controllers" folder or whatever name and a file called "nominator.js" that is going to be our controller, this file will look like this:
var mongoose = require('mongoose'), models = require('../models/nomination.js'), Nomination, db; models.defineModels(mongoose, function() { Nomination = mongoose.model('Nomination'); db = mongoose.connect('mongodb://nominator:nominat0r@ds029257.mongolab.com:29257/nomi-nation'); }); var NOMINATOR = {}; function findIndexByKeyValue(obj, key, value) { var l = obj.length; for (var i = 0; i < l; i++) { if (obj[i][key] == value) { return i; } } return null; } /** * Add vote * @nomination object * @voterId string * @userId string * @callback function */ NOMINATOR.vote = function(nomination, voterId, userId, callback) { //TODO: check we dont want more than 10 users per nomination var isPresent = -1; try { isPresent = nomination.voters.indexOf(voterId); } catch (e){ isPresent = -1; } if (isPresent < 0){ nomination.voters.push(voterId); } //TODO: change to an actual mongo function var index = findIndexByKeyValue(nomination.users, "_id", userId); nomination.users[index].votes += 1; nomination.save(callback); //Nomination.update({_id :nomination.id}, {users: nomination.users}, callback); }; /** * Add user * @nomination object * @user object * @callback function */ NOMINATOR.addUser = function(nomination, user, callback) { //TODO: check we dont want more than 10 users per nomination var isPresent = nomination.erased.indexOf(user._id); if (isPresent >= 0){ callback(new Error('User can\'t be added'), null); return; } if (user instanceof Array){ nomination.users = user; }else{ nomination.users.push(user); } nomination.save(callback); //Nomination.update({_id :nomination.id}, {users: nomination.users}, callback); }; /** * Erase user * @nomination object * @user object * @callback function */ NOMINATOR.eraseUser = function(nomination, user, callback) { nomination.users.remove(user); //erased from the users list nomination.erased.push(user._id); //add to the erased so we dont add them again nomination.save(callback); //Nomination.update({_id :nomination.id}, {users: nomination.users, erased: nomination.erased}, callback); }; /** * Create nomination * @nomination object * @callback function */ NOMINATOR.createNomination = function(nomination, callback) { var myNomination = new Nomination(nomination); myNomination.save(callback); }; /** * Erase nomination * @nominationid string * @callback function */ NOMINATOR.eraseNomination = function(nominationid, callback) { Nomination.erase({'_id' : nominationid }, callback); }; /** * find nominations the user own * @userid fb userid * @callback function * */ NOMINATOR.findMyNominations = function(userId, callback) { Nomination.where('owner', userId) .where('active', true) .run(callback); }; /** * find nominations the user voted * @userId fb userid * @callback function * */ NOMINATOR.findVoted = function(userId, callback) { Nomination.where('voters').in([userId]) .where('active', true) .run(callback); }; /** * find nominates where the user was nominated * @userId fb userid * @callback function * */ NOMINATOR.findNominated = function(userId, callback) { Nomination.where('users._id').in([userId]) .where('active', true) .run(callback); }; // Exporting functions module.exports = NOMINATOR;
Line 1: loading the mongoose modules
2: loading the models, we only export one function
3: our local variables
5-8: we start using the function we exported in "models.js" and we make an instance of the model "nomination" and we connect to the db
10: Lets create our object that will hold all the functionality to export it at the end
11: A small helper function to look for indexes inside the arrays
23-47: Adding votes, lets first check if the user voted its already in the list, if not to added if yes, to add one vote to this victim nominated, we save the model that function will make this change to go directly to the mongodb, lets call the callback to show the results for whom call us, this callback will have as parameters "error" and "doc"
68-79: Erasing users, first lets erase him for the list of users and then add them to the list of erased, save and call the callback
81-89: Creating nominations, we get as a parameter an object with the attributes needed to create a nomination, we make an instance of it and save it, calling the callback
91-125: Searching, search is easy using query, we use the base model and we keep adding whatever we are looking for, e.g,: "where('owner', userId)", here we are looking where the nomination owner is the userId that we get as a parameter, then we check that this nomination is active and at the end we run the query with "run(callback)" and send the results to the callback, this will be the same for all the searching just with different parameters
128: Lets export our object with all the functionality
We are done!!!, we have our models and our controller to handle them in our app, next time we will see how make some testing for our models and routes
The model picture was created using cacoo :) online
Fork the code in github:
Greetings
Mongoose creates virtual id getters for you by default so no need to define them yourself :)
ReplyDeletesweet, thanks
Delete