Skip to content

Instantly share code, notes, and snippets.

@marciejones
Forked from bclinkinbeard/referenced_mongo_json.md
Last active January 18, 2023 10:09
Show Gist options
  • Save marciejones/92552486b4681fe1c3a6b59a9485194a to your computer and use it in GitHub Desktop.
Save marciejones/92552486b4681fe1c3a6b59a9485194a to your computer and use it in GitHub Desktop.
Initializing MongoDB collections from JSON files using Node.js and Mongoose

Initializing MongoDB collections from JSON files using Node.js and Mongoose

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment