If you're searching for a way to store objects of different types in the same collection while maintaining them as distinguishable first class objects, the mongoose .discriminator()
method is what you need.
It's crucial to note that the concept of the "same collection" plays a significant role in how the .populate()
function operates and how the reference is defined in the parent model. While you can only point to one model for a reference, there are mechanisms in place to make it seem like there are multiple models at play.
For instance, using the example below:
var util = require('util'),
async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/gunshow');
//mongoose.set("debug",true);
var scenarioSchema = new Schema({
"name": String,
"guns": [{ "type": Schema.Types.ObjectId, "ref": "Gun" }]
});
function BaseSchema() {
Schema.apply(this, arguments);
// Common Gun stuff
this.add({
"createdAt": { "type": Date, "default": Date.now }
});
}
util.inherits(BaseSchema, Schema);
var gunSchema = new BaseSchema();
var ak47Schema = new BaseSchema({
// Ak74 stuff
});
ak47Schema.methods.shoot = function() {
return "Crack!Crack";
};
var m16Schema = new BaseSchema({
// M16 Stuff
});
m16Schema.methods.shoot = function() {
return "Blam!!"
};
var Scenario = mongoose.model("Scenario", scenarioSchema);
var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );
// Remaining code for adding guns to scenarios, populating, querying, etc.
This setup allows you to have different schemas for various first-class objects, including unique methods attached to each model. Despite all data being stored in a single "guns" collection with its corresponding model, mongoose uses a special "__t" field to differentiate between the types referenced by the discriminator.
Methods specific to each schema, such as .shoot()
, are applied accordingly when interacting with the objects. Additionally, individual models like Ak47
can be utilized for queries or updates, automatically applying the "__t" value for differentiation.
In essence, although the storage appears as one collection, the implementation mimics multiple collections, offering the advantages of grouped operations while supporting polymorphism effectively.