Can you populate an array in a mongoose schema with references to a few different schema options?
To clarify the question a bit, say I have the following schemas:
var scenarioSchema = Schema({
_id : Number,
name : String,
guns : []
});
var ak47 = Schema({
_id : Number
//Bunch of AK specific parameters
});
var m16 = Schema({
_id : Number
//Bunch of M16 specific parameters
});
Can I populate the guns array with a bunch of ak47 OR m16? Can I put BOTH in the same guns array? Or does it require a populate ref in the assets array, like this, which limits it to a single specific type?
guns: [{ type: Schema.Types.ObjectId, ref: 'm16' }]
I know I could just have separate arrays for different gun types but that will create an insane amount of extra fields in the schema as the project scales, most of which would be left empty depending on the loaded scenario.
var scenarioSchema = Schema({
_id : Number,
name : String,
ak47s : [{ type: Schema.Types.ObjectId, ref: 'ak47' }],
m16s: [{ type: Schema.Types.ObjectId, ref: 'm16' }]
});
So back to the question, can I stick multiple schema references in a single array?
What you are looking for here is the mongoose
.discriminator()
method. This basically allows you to store objects of different types in the same collection, but have them as distinquishable first class objects.Note that the "same collection" principle here is important to how
.populate()
works and the definition of the reference in the containing model. Since you really can only point to "one" model for a reference anyway, but there is some other magic that can make one model appear as many.Example listing:
And output
You can also uncomment the
mongoose.set("debug",true)
line in the listing to see how mongoose is actually constructing the calls.So what this demonstrates is that you can apply different schemas to different first class objects, and even with different methods attached to them just like real objects. Mongoose is storing these all in a "guns" collection with the attached model, and it will contain all "types" refernced by the discriminator:
But also each different "type" is referenced with it's own model in a special way. So you see that when mongoose stores and reads the object, there is a special
__t
field which tells it which "model" to apply, and hence attached schema.As one example we call the
.shoot()
method, which is defined differently for each model/schema. And also you can still use each as a model by itself for queries or other operations, sinceAk47
will automatically apply the__t
value in all query/upates.So though the storage is in one collection it can appear to be many collections, but also has the benefit of keeping them together for other useful operations. This is how you can apply the kind of "polymorphism" you are looking for.