Mongoose

For discussions about game development that does not fit in any of the other topics.
Post Reply
User avatar
hallsofvallhalla
Site Admin
Posts: 12023
Joined: Wed Apr 22, 2009 11:29 pm

Mongoose

Post by hallsofvallhalla »

Anyone use it with Mongodb and Nodejs? Alternatives?
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Mongoose

Post by Jackolantern »

I have used it a little bit, and have found it pretty simple to work with. As for alternatives, you can use Waterline, which is the ORM of SailsJS, or you could take a look at this list here. It does seem that Mongoose is basically the standard, however.
The indelible lord of tl;dr
User avatar
kaos78414
Posts: 507
Joined: Thu Jul 22, 2010 5:36 am

Re: Mongoose

Post by kaos78414 »

I'm using it for a couple projects I've got going, and I also use it at work alongside Sequelize for mySQL. I like it, but tbh I haven't explored any alternatives. Anything specific you wanna know?
w00t
User avatar
hallsofvallhalla
Site Admin
Posts: 12023
Joined: Wed Apr 22, 2009 11:29 pm

Re: Mongoose

Post by hallsofvallhalla »

I just find Mongo to be a bit bloated at times and because I do not use it that often I spend too much time figuring out how to do stuff through nodejs with mongo so looking for something quick and clean.
User avatar
kaos78414
Posts: 507
Joined: Thu Jul 22, 2010 5:36 am

Re: Mongoose

Post by kaos78414 »

Well Mongoose is just an ODM built on top of the mongo driver. Mongoose may be more bloat then you need.

That said, I found it pretty quick and easy to set up. I'll give you an example of a model and a query based on that model (this is taken from a project I'm working on, it is currently not complete, so there are some validations and callbacks missing atm):

User model:

Code: Select all

var bcrypt = require('bcryptjs');

var notEmtpy = function(val) {
    return val && val.length;
};

module.exports = function(mongoose) {
    var User = {
        name: 'User',
        schema: mongoose.Schema({
            email: String,
            password: { type: String, set: function(pwd) { // encrypt password
                var salt = bcrypt.genSaltSync(10); // generate salt
                return bcrypt.hashSync(pwd, salt); // encrypt against salt
            }},
            created: { type: Date, default: Date.now },
            updated: { type: Date, default: Date.now },
            last_ip: String, // last log in IP, used to check against remember me cookie
            current_ip: String, // current log in IP, used to check against remember me
            active: { type: Boolean, default: true },
            reset_password_token: String,
            reset_sent_at: Date
        })
    };

    // instance methods
    User.schema.methods = {
        passwordMatches: function(pwd) {
            return bcrypt.compareSync(pwd, this.password);
        }
    };

    // lifecycle callbacks
    User.schema.pre('save', true, function(next, done) {
        console.log('User trying to be saved!');
        next();
        //done(); // that 'true' flag in the pre callback makes it so that the user will not save until all of the lifecycle callbacks have passed done();
        // mine is currently commented out so that I don't accidentally save any user records while testing
    });

    // validation
    User.schema.path('email').validate(function(val, fn) {
        fn(notEmtpy(val));
    }, 'Email cannot be blank.');

    User.schema.path('email').validate(function(val, fn) {
        // Check only when it is a new user or when email field is modified
        if (this.isNew || this.isModified('email')) {
            var User = mongoose.model('User');
            User.find({ email: val }).exec(function (err, users) {
                fn(!err && users.length === 0);
            });
        } else {
            fn(true);
        }
    }, 'Email already exists.');

    User.schema.path('password').validate(function(val, fn) {
        fn(notEmtpy(val));
    }, 'Password cannot be blank.');

    return User;
};
That's in /src/models/user.js

And the file that picks it up is /src/models/index.js

Code: Select all

var fs       = require('fs'),
    path     = require('path'),
    Mongoose = require('mongoose'),
    lodash   = require('lodash'),
    mongoose = Mongoose.connect('mongodb://' + config.db.host), // config in my case is a global variable where I can pass environment
    db       = {};

fs
    .readdirSync(__dirname)
    .filter(function(file) {
        return (file.indexOf('.') !== 0) && (file !== 'index.js');
    })
    .forEach(function(file) {
        var model = require(path.join(__dirname, file))(mongoose);
        db[model.name] = mongoose.model(model.name, model.schema);
    });

module.exports = lodash.extend({
    mongoose: mongoose,
    Mongoose: Mongoose
}, db);
Now in app.js I can do:

Code: Select all

var db = require('./models'),
    mongoose = db.mongoose.connection; //load up the DB

// access models with db.User
// for example:
app.post('/sign_in', function(req, res, next) {
    db.User.findOne({ 'email': req.param('email') }, function(err, user) {
        if (err) {
            throw err;
        } else if (typeof user == 'undefined' || user === null) {
            req.session.errors = { err: "The email or password you entered is incorrect." };
            res.redirect(req.headers['referer']); // this plays into my flash messages in my case
        } else {
            // check password
            // logged in, redirect to appropriate page, or do whatever else
        }
    });
});


//handle mongo errors
mongoose.on('error', console.error.bind(console, 'Mongo Connection Error: '));

//once the mongo connection is open, start the HTTP server
mongoose.once('open', function() {
    http.createServer(app).listen(app.get('port'), function() {
      // server running!
    });
});
Does that help?
w00t
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Mongoose

Post by Jackolantern »

Waterline is definitely lighter than Mongoose, but it doesn't offer as many features. You may even be interested in checking out all of SailsJS.
The indelible lord of tl;dr
User avatar
a_bertrand
Posts: 1536
Joined: Mon Feb 25, 2013 1:46 pm

Re: Mongoose

Post by a_bertrand »

Somehow I feel always the black sheep with you guys. I use just the most basic Monogo node.js lib and even if I can't say I'm happy by all this non-sense async call back syntax, I'm still pretty happy by the fact I can simply add as much stuff to my objects as I want.

BTW keep in mind there is some restrictions with Mongo which I wasn't aware:
Arrays cannot have negative index (those will not be stored). And yes I was using it (or trying).
Another thing which may happen less frequently: you can't add your own properties to arrays, those "mixed" objects will not be stored with Mongo.

Beside those limitations, my main drawback with Mongo is the lack of foreign keys which I could use in some cases.
Creator of Dot World Maker
Mad programmer and annoying composer
User avatar
hallsofvallhalla
Site Admin
Posts: 12023
Joined: Wed Apr 22, 2009 11:29 pm

Re: Mongoose

Post by hallsofvallhalla »

the code above is my point. Look at all that code you must write. I want simple query functions and that is it. Save data, pull data, done.

Not the black sheep but rather another valuable point of the conversations.
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Mongoose

Post by Jackolantern »

hallsofvallhalla wrote:the code above is my point. Look at all that code you must write. I want simple query functions and that is it. Save data, pull data, done.

Not the black sheep but rather another valuable point of the conversations.
Seriously check out Waterline. I think it is what you need. The schemas are very basic, and the querying is about as simple as it gets.

You may also want to check out MongoJS, which aims to reduce the number of lines needed by simulating the mongo command-line client in node code.
The indelible lord of tl;dr
User avatar
a_bertrand
Posts: 1536
Joined: Mon Feb 25, 2013 1:46 pm

Re: Mongoose

Post by a_bertrand »

Actually mongojs could have been the solution for me. It seems to reduce the number of async calls you need. Yet I'm far from being sure it supports all what I need. For example I do text search which requires a couple of "commands". Not sure if that's supported.

Waterline is for me a no go. Basically because I don't want a schema. The client defines alone most of the data. I know it's not really smart or secure but yet this is what I choose at the moment.
Creator of Dot World Maker
Mad programmer and annoying composer
Post Reply

Return to “General Development”