uncategorized

Mongo Inception, A Schema Within A Schema

by Andrew Akagawa


Grow Your Practice with Reviews and Testimonials

I recently hit a wall trying to create a review service for our new website healthrate using Mongoose. For anyone who has used Mongoose to the point of arrays within arrays within arrays, you may reach a point where you miss the good old days of SQL based programming. In my googling and continued learning of Mongoose, I stumbled upon the solution of Schemas referencing Schemas. Unfortunately, I lost a day trying to figure it out, so I thought I would write a quick blog to help others figure it out faster.

My example has a user schema with various information, and a review schema in which others can leave reviews for a user.

Step 1: Defining the User Schema

Here is an example of a User schema file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var mongoose = require('mongoose');
var Users = new mongoose.Schema({
username: { type: String, unique: true },
address: String,
city: String,
state: String,
zip: String,
reviews:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'Reviews'
}],
});
module.exports = mongoose.model('User', Users);

The key thing to notice is the reviews array, which has subdocuments containing an ObjectId type, referencing ‘Reviews’. We will define ‘Reviews’ in the next step. The actual review data that will be populated here will just be an array of ObjectIds that reference reviews from our separate review schema.

Step 2: Defining the Review Schema

Hooray! No longer does this have to be an array nestled in my user schema! Here is an example of my review schema:

1
2
3
4
5
6
7
8
var mongoose = require('mongoose');
var Reviews = new mongoose.Schema({
review: { type: String, maxlength: '10000' },
date: Date
});
module.exports = mongoose.model('Reviews', Reviews);

You can now see in our mongoose model where ‘Reviews’ ties to the User reviews reference in Step 1. The ObjectIds created for each review will be referenced by the User schema.

Step 3: Saving and Returning a Review

You’ve defined your schemas. Now you’re ready to use them in your server side javascript.

Be sure to reference both your user and review schema files if called in separate files. Mine are saved in the models directory and referenced as shown:

1
2
var User = require('../models/user');
var Review = require('../models/review');

So, say you have a new set of review data. Below we have it defined in a review variable. We also know the ObjectId for the user being updated and have it defined as mySpecifiedUserId. Here is my code to save and return the data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Create a new Review with the data
var postReview = new Review(review)
// First, save the new review to the Reviews collection
postReview.save(function (err) {
if (err) {
done(err);
};
// Next, find the User you want to leave the review for by ObjectId - mySpecifiedUserId and push the review ObjectId only
// with the option to return the review data
User.findOneAndUpdate(
{_id:mySpecifiedUserId},
{"$push":{"reviews":postReview._id}},
{upsert:true, select:'username address city state zip username address city state zip reviews'}
// populate and return the review data
).populate('reviews').exec(function(err, data) {
console.log(data);
});
});

If you are familiar with Mongoose, then you should recognize most of this. Above, we are saving the review to the Reviews schema, and pushing only the review ObjectId to the reviews array of the User schema. The returned data array will contain all of the User data in the document as well as the associated nested data in the reviews array.

The one important thing to note is that you need to use populate to actually return the data in the review array, otherwise it will just return the ObjectIds for the reviews.

Why Schemas Within Schemas?

On a final note, why this helps? As of the time I am writing this, Mongoose doesn’t really support doing any kind of operations or modifications to arrays within schemas. So, if I simply defined my reviews array within the User schema, it would be difficult to find and modify a single review. But with a nested schema and a MEAN stack, you can easily pull an array of reviews for a particular User, and then reference the ObjectId for each review to modify the Reviews schema directly.

Hope this helps!

If so, please like us on any of your favorite social medias and/or Share .


Grow Your Practice. Websites | Online Marketing | Administrative Tools

SubmitHealth - Grow Your Practice. Websites | Online Marketing | Administrative Tools

Share