Was Sie hier suchen, ist der Mungo .discriminator()
Methode. Dies erlaubt Ihnen grundsätzlich, Objekte unterschiedlichen Typs in derselben Sammlung zu speichern, sie aber als unterscheidbare Objekte erster Klasse zu haben.
Beachten Sie, dass das Prinzip der "gleichen Sammlung" hier wichtig ist, wie .populate()
Werke und die Definition der Referenz im enthaltenden Modell. Da Sie wirklich nur auf "ein" Modell als Referenz verweisen können, gibt es jedoch eine andere Magie, die ein Modell als mehrere erscheinen lassen kann.
Beispielliste:
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 );
async.series(
[
// Cleanup
function(callback) {
async.each([Scenario,Gun],function(model,callback) {
model.remove({},callback);
},callback);
},
// Add some guns and add to scenario
function(callback) {
async.waterfall(
[
function(callback) {
async.map([Ak47,M16],function(gun,callback) {
gun.create({},callback);
},callback);
},
function(guns,callback) {
Scenario.create({
"name": "Test",
"guns": guns
},callback);
}
],
callback
);
},
// Get populated scenario
function(callback) {
Scenario.findOne().populate("guns").exec(function(err,data) {
console.log("Populated:\n%s",JSON.stringify(data,undefined,2));
// Shoot each gun for fun!
data.guns.forEach(function(gun) {
console.log("%s says %s",gun.__t,gun.shoot());
});
callback(err);
});
},
// Show the Guns collection
function(callback) {
Gun.find().exec(function(err,guns) {
console.log("Guns:\n%s", JSON.stringify(guns,undefined,2));
callback(err);
});
},
// Show magic filtering
function(callback) {
Ak47.find().exec(function(err,ak47) {
console.log("Magic!:\n%s", JSON.stringify(ak47,undefined,2));
callback(err);
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
Und ausgeben
Populated:
{
"_id": "56c508069d16fab84ead921d",
"name": "Test",
"__v": 0,
"guns": [
{
"_id": "56c508069d16fab84ead921b",
"__v": 0,
"__t": "Ak47",
"createdAt": "2016-02-17T23:53:42.853Z"
},
{
"_id": "56c508069d16fab84ead921c",
"__v": 0,
"__t": "M16",
"createdAt": "2016-02-17T23:53:42.862Z"
}
]
}
Ak47 says Crack!Crack
M16 says Blam!!
Guns:
[
{
"_id": "56c508069d16fab84ead921b",
"__v": 0,
"__t": "Ak47",
"createdAt": "2016-02-17T23:53:42.853Z"
},
{
"_id": "56c508069d16fab84ead921c",
"__v": 0,
"__t": "M16",
"createdAt": "2016-02-17T23:53:42.862Z"
}
]
Magic!:
[
{
"_id": "56c508069d16fab84ead921b",
"__v": 0,
"__t": "Ak47",
"createdAt": "2016-02-17T23:53:42.853Z"
}
]
Sie können mongoose.set("debug",true)
auch auskommentieren Zeile in der Auflistung, um zu sehen, wie Mongoose die Aufrufe tatsächlich erstellt.
Das zeigt also, dass Sie unterschiedliche Schemas auf unterschiedliche erstklassige Objekte anwenden können, und sogar mit unterschiedlichen Methoden, die an sie angehängt sind, genau wie echte Objekte. Mongoose speichert diese alle in einer "Waffen"-Sammlung mit dem angehängten Modell, und sie wird alle "Typen" enthalten, auf die der Diskriminator verweist:
var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );
Aber auch jeder unterschiedliche „Typ“ wird mit einem eigenen Modell in besonderer Weise referenziert. Sie sehen also, wenn Mongoose das Objekt speichert und liest, gibt es einen speziellen __t
Feld, das ihm mitteilt, welches "Modell" angewendet werden soll, und damit das angehängte Schema.
Als ein Beispiel nennen wir .shoot()
Methode, die für jedes Modell/Schema unterschiedlich definiert ist. Und Sie können seit Ak47
auch noch jedes einzeln als Modell für Abfragen oder andere Operationen verwenden wendet automatisch den __t
an Wert in allen Abfragen/Updates.
Obwohl sich der Speicher in einer Sammlung befindet, kann es so aussehen, als wären es viele Sammlungen, hat aber auch den Vorteil, dass sie für andere nützliche Operationen zusammengehalten werden. So können Sie die Art von "Polymorphismus" anwenden, nach der Sie suchen.