Ce que vous cherchez ici est la mangouste .discriminator()
méthode. Cela vous permet essentiellement de stocker des objets de différents types dans la même collection, mais de les avoir comme des objets de première classe distincts.
Notez que le principe de "même collection" ici est important pour la façon dont .populate()
travaux et la définition de la référence dans le modèle contenant. Puisque vous ne pouvez vraiment pointer que vers "un" modèle pour une référence de toute façon, mais il y a une autre magie qui peut faire apparaître un modèle comme plusieurs.
Exemple de liste :
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();
}
);
Et sortie
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"
}
]
Vous pouvez également décommenter le mongoose.set("debug",true)
ligne dans la liste pour voir comment la mangouste construit réellement les appels.
Donc, ce que cela démontre, c'est que vous pouvez appliquer différents schémas à différents objets de première classe, et même avec différentes méthodes qui leur sont attachées, tout comme de vrais objets. Mongoose les stocke tous dans une collection "guns" avec le modèle attaché, et elle contiendra tous les "types" référencés par le discriminateur :
var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );
Mais aussi chaque "type" différent est référencé avec son propre modèle d'une manière spéciale. Vous voyez donc que lorsque la mangouste stocke et lit l'objet, il existe un __t
spécial champ qui lui indique quel "modèle" appliquer, et donc le schéma attaché.
Comme exemple, nous appelons le .shoot()
méthode, qui est définie différemment pour chaque modèle/schéma. Et aussi vous pouvez toujours utiliser chacun comme un modèle par lui-même pour les requêtes ou d'autres opérations, puisque Ak47
appliquera automatiquement le __t
valeur dans toutes les requêtes/mises à jour.
Ainsi, bien que le stockage se trouve dans une collection, il peut sembler y avoir plusieurs collections, mais a également l'avantage de les conserver ensemble pour d'autres opérations utiles. C'est ainsi que vous pouvez appliquer le type de "polymorphisme" que vous recherchez.