2016-02-17 11 views
11

È possibile popolare una matrice in uno schema di mangusta con riferimenti a diverse opzioni dello schema?Riferimenti di più schemi nell'array a schema singolo - mangusta

Per chiarire la questione un po ', dice che ho le seguenti schemi:

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 
}); 

Posso compilare la matrice pistole con un gruppo di ak47 O m16? Posso inserire ENTRAMBE nello stesso array di pistole? O richiede un refulante nella matrice di risorse, come questo, che lo limita a un singolo tipo specifico?

guns: [{ type: Schema.Types.ObjectId, ref: 'm16' }] 

So che potrei semplicemente avere array separati per i diversi tipi di pistola, ma che creerà una quantità folle di campi aggiuntivi nello schema come le scale di progetto, la maggior parte dei quali sarebbe rimasto vuoto a seconda dello scenario caricato.

var scenarioSchema = Schema({ 
    _id  : Number, 
    name : String, 
    ak47s : [{ type: Schema.Types.ObjectId, ref: 'ak47' }], 
    m16s: [{ type: Schema.Types.ObjectId, ref: 'm16' }] 
}); 

Quindi tornando alla domanda, posso attaccare più riferimenti dello schema in un singolo array?

risposta

16

Quello che stai cercando è il metodo mangusta .discriminator(). Questo in pratica consente di memorizzare oggetti di tipi diversi nella stessa collezione, ma li ha come oggetti di prima classe distinqui.

Si noti che il principio "stessa collezione" qui è importante per il modo in cui funziona .populate() e la definizione del riferimento nel modello contenente. Dal momento che in realtà puoi solo puntare a un "modello" per riferimento, ma c'è qualche altra magia che può far apparire un modello come molti.

Esempio messa in vendita:

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(); 
    } 
); 

E uscita

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" 
    } 
] 

Si può anche togliere il commento alla linea di mongoose.set("debug",true) nella lista per vedere come mangusta è in realtà costruendo le chiamate.

Quindi ciò che dimostra è che è possibile applicare schemi diversi a diversi oggetti di prima classe e anche con metodi diversi ad essi collegati, proprio come gli oggetti reali. Mongoose sta memorizzando questi tutti in una collezione "cannoni" il modello allegato, e conterrà tutti i "tipi" refernced dal discriminatore:

var Gun = mongoose.model("Gun", gunSchema); 
var Ak47 = Gun.discriminator("Ak47", ak47Schema); 
var M16 = Gun.discriminator("M16", m16Schema); 

Ma anche ogni "tipo" diverso si fa riferimento con il proprio modello un modo speciale Così vedi che quando la mangusta memorizza e legge l'oggetto, c'è un campo speciale __t che indica quale "modello" applicare, e quindi lo schema allegato.

Come esempio, si chiama il metodo .shoot(), che è definito in modo diverso per ogni modello/schema. Inoltre, è possibile utilizzarli singolarmente come modello per query o altre operazioni, poiché Ak47 applicherà automaticamente il valore __t in tutte le query/aggiornamenti.

Quindi, se lo spazio di archiviazione è in una raccolta, può sembrare che siano molte raccolte, ma ha anche il vantaggio di tenerle insieme per altre operazioni utili. È così che puoi applicare il tipo di "polimorfismo" che stai cercando.

+0

Wow, questo è stato super informativo! Grazie!! – BrentShanahan

Problemi correlati