Skip to content

Instantly share code, notes, and snippets.

@bclinkinbeard
Created March 15, 2013 16:56
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save bclinkinbeard/5171359 to your computer and use it in GitHub Desktop.
Save bclinkinbeard/5171359 to your computer and use it in GitHub Desktop.
Populating referenced collections in MongoDB from JSON files using Node.js and Mongoose

Populating referenced collections in MongoDB 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!

@seenickcode
Copy link

This helps a lot. Thank you.

@joelmgallant
Copy link

Indeed - very useful, though I might also add that it's sometimes necessary to chain these types of actions together using a library like: https://github.com/caolan/async

In my case, saves weren't being finished before the query, so I had to set up a series structure in order to ensure the data could be populated.

@jhyland87
Copy link

Im guessing that Mongooses populate method wasn't around when you wrote this?

@singhaishwarya
Copy link

how to find first and last entry of a particular field using refrence from other table.??

@arun-topagi
Copy link

arun-topagi commented Jan 20, 2018

logEntry._food = foodMap[ logEntry.food_name ];
In this logEntry.food_name where it's pointing because logEntry don't have food_name field

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