Testing Mongoose model required properties - node.js

I recently started developing apps with node.js, express, and mongoose. I decided to use mocha as a testing framework and is wondering how would I unit test mongoose.model properties for validity.
So if I had a model defined like this:
var userSchema = new Schema({
name: {type: String, required: true}
});
var userModel = new mongoose.model('User', userSchema);
I'm assuming that stating "require: true" means that userSchema.name must be defined and not null.
How do I test that when I instantiate a userModel, I must provide it with an object containing a name property that is not null or undefined?
Thanks

Check out Mockgoose for writing unit tests with mongoose models without the need to have a mongodb instance running.
You could write a simple test like this:
var mongoose = require('mongoose'),
mockgoose = require('mockgoose');
mockgoose(mongoose);
var Schema = mongoose.Schema;
var SimpleSchema = new Schema({
name: {
type: String,
required: true
}
});
mongoose.model('SimpleModel', SimpleSchema);
it('fails to save document with missing name', function(done) {
var simpleModel = new SimpleModel({
name: undefined
});
simpleModel.save(function(err) {
should.exist(err);
done();
});
});
Then define different tests with different values for name (null, undefined, etc.) or even an empty object (i.e. an object without name property).

Related

What is an equivalent work around to $setOnInsert in mongoose

I have below collection structure in mongodb. Say
Collection - student - _id,firstname,lastname,class
Now I want to insert 2 extra columns say marks as array{mark1:m1,mark2:m2}when inserting a newrow`.
I did it as below but it inserted record excluding marks values.
var student=new Student({
_id:id,
firstname:result.fname,
lastname:result.lname,
class:result.class,
marks:{
mark1:result.mark.m1,
mark2:result.mark.m2
}
})
Is this possible in Mongoose?
I came across $setOnInsert, but not sure whether this fits here?
So if it fits, is there any equivalent workaround to use MongoDb's $setOnInsert? if not what approach I could use?
Yes, it's possible but that depends on the options set when defining your schema. You don't necessarily need to use the $setOnInsert operator when inserting a new record, the save() method on the model suffices.
The strict option ensures that values added to your model instance that were not specified in the schema gets saved or not to the db.
For example, if you had defined your schema like this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var studentSchema = new Schema({
firstname: String,
lastname: String,
class: String
})
var Student = mongoose.model('Student', studentSchema);
var student= new Student({
_id: id,
firstname: result.fname,
lastname: result.lname,
class: result.class,
marks: {
mark1: result.mark.m1,
mark2: result.mark.m2
}
});
student.save(); // marks is not saved to the db
But if you set the strict option to false:
var studentSchema = new Schema({..}, { strict: false });
var student= new Student({
_id: id,
firstname: result.fname,
lastname: result.lname,
class: result.class,
marks: {
mark1: result.mark.m1,
mark2: result.mark.m2
}
});
student.save(); // marks is now saved to the db!!
NOTE: The strict option is set to false in mongoose v2 by default for backward compatibility. Set it to true and sleep peacefully. Do not set to false unless you have good reason.

How to get all nested document objects in mongoose

I am new to mongo DB. I am developing an application using MEAN stack. On my back-end I have two models - Feature & Project.
Project schema has an attribute called 'features' which is an array of Feature objects.
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ProjectSchema = new Schema({
name: {
type: String,
default: '',
trim: true
},
features:{
type: [Schema.ObjectId],
ref: 'Feature'
}
});
/**
* Statics
*/
ProjectSchema.statics.load = function(id, cb) {
this.findOne({
_id: id
})
.populate('features')
.exec(cb);
};
mongoose.model('Project', ProjectSchema);
Please note that I have separate files for Feature and Project schema. I am registering both schema as mongoose models.
I also have a controller as well for projects which exports the following middle-ware function:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Project = mongoose.model('Project'),
Testcase = mongoose.model('Feature'),
_ = require('lodash');
/**
* Find project by id
*/
exports.project = function(req, res, next, id) {
Project.load(id, function(err, project) {
if (err) return next(err);
if (!project) return next(new Error('Failed to load project ' + id));
console.log(project.features.length);
req.project = project;
next();
});
};
I would have expected all details of Feature objects in the project object above since I have used ".populate('features')" in the static load function of Project schema. But it is not happening, it returns an empty array for features attribute. Could anyone please tell me what am I missing here?
Project schema has an attribute called 'features' which is an array of Feature objects.
Careful there. What you need is an array of ObjectIds that correspond to Feature documents.
I think you need to specify the project.features schema like this:
features: [{type: Schema.ObjectId, ref: 'Feature'}]
The populate function only works if both the code and the data are all 100% correct and it's very easy to make a mistake. Can you post the sample data of the Project document you are loading? We need to make sure features is really an array, really contains ObjectIds not strings or objects, etc.

Mongoose referencing models in other models

I am working on an express/node app, using mongodb and mongoose to model users, players, teams, etc. Between these models I am using references with ObjectIDs, so between players and teams there is a connector model RosterSpot which holds a team_id and player_id, both with the Schema type of ObjectID.
Anyways, I am running into problems trying to reference RosterSpots inside of the Team and Player models. I would like to have a method for Players that grabs all their teams, and vice versa for Teams. First, given this code in roster_spot.js
// Synchronously load model dependecies, so foreign model calls can be made
var fs = require('fs');
var models_path = __dirname;
fs.readdirSync(models_path).forEach(function (file) {
if (~file.indexOf('.js')) require(models_path + '/' + file);
})
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var Team = mongoose.model('Team');
var Player = mongoose.model('Player');
var RosterSpotSchema = new Schema({
team_id: {type: ObjectId, required: true},
player_id: {type: ObjectId, required: true}
});
....
RosterSpotSchema.statics.getTeamsForPlayer = function(player_id, callback) {
this.getTeamIdsForPlayer(player_id, function(ids){
Team.find({ _id: { $in: ids } }, function(err, teams){
callback(teams);
});
});
};
...
this works perfectly fine, as this RosterSpot model calls the Team.find() and Player.find() methods without a problem.
The problem comes when I try to make that call in the Player or Team model in the following method in player.js:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var RosterSpot = mongoose.model('RosterSpot');
var PlayerSchema = new Schema({...});
...
PlayerSchema.methods.getTeams = function (callback) {
RosterSpot.getTeamsForPlayer(this._id, function(teams){
callback(teams);
})
};
When I have the var RosterSpot = mongoose.model('RosterSpot'); in there, it throws a "MissingSchemaError: Schema has not been registered for 'RosterSpot'."
I've tried loading in the models via require and async stuff but nothing is working.
The crazy thing is, though, that I've been able to call these sorts of methods for users and players, using the connector model Family and that all works fine. I don't even have to initialize a variable for Family in users.js, which is weird but it works...
I have thought that maybe it is my testing environment that might mess with loading files, but when I start the server it also throws that error. Would be helpful to know if this is even possible, and any insight to this problem would be much appreciated.

how to convert mongoose js model to object

i am working with node.js and mongoosejs framwork for mongodb. I am trying to convert a mongoose model to an object, I was able to do that, but am getting only fewer elements rather than getting all. Below code which I tried.
user.js
var schema = new Schema({
name:{ type:string },
title:{ type:string, default:"mr" }
});
module.exports = mongoose.model('Users', schema);
usermanager.js
var User = require(../user.js);
var user = new User();
console.log(user.toString());
//printed as {_id:2583457assda312, title:'mr'}
i am expecting name key in that object. i have also tryed toObject it also giveing me the same response.
ther is any posiblty to achive this?
Your usage is intended to be like this:
var user = new User({ name: "Fred" })
and you will get the values from what you have defined, so in this case:
//printed as {_id:2583457assda312, name: "Fred", title:'mr'}
Or you supply your title as here:
var user = new User({ name: "Wilma", title: "Ms" })
and again get your output
//printed as {_id:2583457assda312, name: "Wilma", title: "Ms"}
If what you are trying to do is inspect the schema there is a paths property on Mongoose schema objects
console.log( user.schema.paths )
And that should give you a definition of the various parts of the schema you defined.

Saving Mongoose object into two collections

Currently I have a node application which uses mongoose to save an object into a MongoDB. I am using a model similar to this:
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var RegistrationSchema = new Schema({
name:{ type: String, default: '', trim: false}
});
mongoose.model('Registration', RegistrationSchema);
Which saves my objects into a collection called registrations.
I save my registrations as such:
var registration = new Registration(data);
registration.save(function(err) {
if (err) {
return callback({
source: 'data_save',
type: 'admin',
errors: err
});
}
else {
return callback(null, data);
}
});
I would also like to save this same object when I create it, into another collection with a different name, such as registrations_new, or something to that effect. I want to duplicate this entry into the new collection. I tried to add the other collection in the connection string, which broke the mongo part entirely, I tried to create a new model called New_Registration, load that Schema and try to save it individually, but I have another issue with that. It seems that Mongoose pairs the schema with the collection, and that there really is no way to overwrite which collection it is saving to.
Anyone have any solution for this?
You can use the same schema in multiple models, so something like this works:
var RegistrationSchema = new Schema({
name:{ type: String, default: '', trim: false}
});
var Registration = mongoose.model('Registration', RegistrationSchema);
var New_Registration = mongoose.model('New_Registration', RegistrationSchema);
var registration = new Registration(data);
registration.save();
var new_registration = new New_Registration(data);
new_registration.save();

Resources