Monday, 24 April 2017

Nesting MongoDB Schema

I've been learning MongoDB from their online Webinar hosted on their website and I'm trying to link Products to a Category (eg. iPhone belongs to Category Mobiles which has ancestors such as Electronics ), however while nesting I'm getting the following error:

MongooseError: Schema hasn't been registered for model "Category".
Use mongoose.model(name, schema)

I saw several questions, by writing Schema.ObjectId and Schema.Types.ObjectId, but I get Cast Error to ObjectId on firing an insert(save) query.

There are few more questions related to these:

  1. How do I make sure, while adding a Product, I also add the Category it's linked to?
  2. What would be a best practice for such kind of scenario (to add subdocuments or reference Schemas)?

PFB Model files, I have written Controller files on top of that in order to perform CRUD operations:

category.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var categorySchema = new Schema({
  _id: { type: String },
  parent: {
    type: String,
    ref: 'Category'
  },
  ancestors: [{
    type: String,
    ref: 'Category'
  }]
});

module.exports.categorySchema = categorySchema;

products.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Category = require('./category');
var fx = require('./fx');

var productSchema = new mongoose.Schema({
  name: { type: String, required: true },
  // Pictures must start with "http://"
  pictures: [{ type: String, match: /^http:\/\//i }],
  price: {
    amount: {
      type: Number,
      required: true,
      set: function(v) {
        this.internal.approximatePriceUSD =
          v / (fx()[this.price.currency] || 1);
        return v;
      }
    },
    // Only 3 supported currencies for now
    currency: {
      type: String,
      enum: ['USD', 'EUR', 'GBP'],
      required: true,
      set: function(v) {
        this.internal.approximatePriceUSD =
          this.price.amount / (fx()[v] || 1);
        return v;
      }
    }
  },
  category: { type: Schema.ObjectId,ref: 'Category'},
  internal: {
    approximatePriceUSD: Number
  }
});

//var schema = new mongoose.Schema(productSchema);

var currencySymbols = {
  'USD': '$',
  'EUR': '€',
  'GBP': '£'
};

/*
 * Human-readable string form of price - "$25" rather
 * than "25 USD"
 */
productSchema.virtual('displayPrice').get(function() {
  return currencySymbols[this.price.currency] +
    '' + this.price.amount;
});

productSchema.set('toObject', { virtuals: true });
productSchema.set('toJSON', { virtuals: true });

module.exports = mongoose.model("Product", productSchema);

Example Output Structure of a Product:

{
    "_id": "**autogeneratedByMongo",
    "name":"iPhone",
    "category":{
        "_id":"Mobiles", 
        "ancestors":["Electronics","Mobiles"]
    }
    ....
}



via Hardik

No comments:

Post a Comment