I recently began working with Node and MongoDB for a small personal project, largely just to learn the technologies. One thing that is fairly simple but that I found far from obvious and lacking in concrete examples was how to populate the part of my database that used referenced collections from the sample JSON data I was starting with. This post attempts to fill that gap using the following code snippets, which are heavily commented inline. You will notice I am using the awesome Mongoose library which makes working with MongoDB very easy.
http.createServer( app ).listen( app.get( 'port' ), function() {
mongoose.connect( 'mongodb://localhost/{YOUR_DB_NAME}' );
var db = mongoose.connection;
db.on( 'error', console.error.bind( console, 'connection error:' ) );
// once the connection is established we define our schemas
db.once( 'open', function callback() {
// independent schema
var FoodSchema = new Schema( {
name: String,
unit: String,
p: Number,
f: Number,
c: Number
} );
// this schema represents a collection whose documents
// will each hold a reference to a single document
// from the FoodSchema collection
var LogEntrySchema = new Schema( {
date: Date,
qty: Number,
// starting the name with an underscore is simply a convention
// to denote this field as a reference
// the type instructs Mongoose to set this up as a reference
// to another document's _id property, which is automatically
// generated by MongoDB. the ref field refers to the Model name
_food: { type: Schema.Types.ObjectId, ref: 'Food' }
} );
// create Mongoose models from our schemas
var Food = mongoose.model( 'Food', FoodSchema );
var LogEntry = mongoose.model( 'LogEntry', LogEntrySchema );
} );
} );
During development I simply defined a route that I could load to trigger a database rebuild. This proved very useful as I would regularly muck things up while working on a new form or other piece of the app. Below is the code for (re)populating the database from JSON files.
var mongoose = require( 'mongoose' )
, _ = require( 'lodash' )
, foodData = require( './mockdata/foodData.json' )
, logData = require( './mockdata/logData.json' );
exports.reset = function( req, res ) {
// get refs to the models we defined above
var Food = mongoose.model( 'Food' );
var LogEntry = mongoose.model( 'LogEntry' );
// clear all existing documents from the collections
Food.find().remove();
LogEntry.find().remove();
// populate the foods collection from json data
// nothing fancy here as Food documents do not reference anything else
for( var i = 0; i < foodData.length; i++ ) {
new Food( foodData[ i ] ).save();
}
// now that the collection is populated we iterate over it
Food.find( function( err, foods ) {
var foodMap = {};
// store _ids of Food documents that Mongo generated upon insert
for( var i = 0; i < foods.length; i++ ) {
var food = foods[i];
// I am mapping the ids to the food names because the LogEntry
// JSON data contained this field thanks to the original source
// data's structure (a spreadsheet).
// You could utilize a more sophisticated lookup here if necessary.
foodMap[ food.name ] = food._id;
}
// populate the LogEntries collection from json data
for( i = 0; i < logData.length; i++ ) {
var logEntry = logData[ i ];
// we find and store food._id on LogEntry for reference
logEntry._food = foodMap[ logEntry.food_name ];
// note that only the fields defined in the schema will be
// persisted to Mongo, so the foodName field we used for
// lookup will not be unnecessarily added to the db
new LogEntry( logEntry ).save();
}
} );
res.redirect( "/" );
};
And there you have it. Far from revolutionary, but hopefully it will help someone get up and running a bit more quickly than I did, though I have to say I was pleasantly surprised with how quickly I was able to be productive with these new (to me) technologies. If you have corrections or suggestions for improvement please leave a comment or fork this Gist.
Enjoy!