2016-02-17 20 views
11

Czy można wypełnić tablicę w schemacie mangusty z odniesieniami do kilku różnych opcji schematu?Wiele odwołań schematów w pojedynczej macierzy schematów - mangusta

wyjaśnić kwestię trochę, że mam następujące schematy:

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 wypełnić tablicę armaty z bandą AK47 LUB M16? Czy mogę umieścić BOTH w tej samej tablicy guns? Lub czy wymaga on wypełnienia ref w tablicy assets, tak jak to, co ogranicza ją do pojedynczego określonego typu?

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

wiem, może po prostu mają osobne tablice dla różnych rodzajów pistoletów, ale że będzie tworzyć insane ilość dodatkowych pól w schemacie jako skalach projektowych, z których większość będzie pozostawione puste w zależności od załadowanego scenariusza.

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

Wracając do pytania, czy mogę wstawić wiele odwołań do schematu w jednej tablicy?

Odpowiedz

16

To, czego szukasz, to metoda mangusty .discriminator(). Zasadniczo pozwala to na przechowywanie obiektów różnych typów w tej samej kolekcji, ale ma je jako wyróżniające się obiekty pierwszej klasy.

Należy pamiętać, że zasada "tego samego zbioru" jest ważna w odniesieniu do sposobu działania .populate() i definicji odniesienia w modelu zawierającym. Ponieważ tak naprawdę możesz wskazać tylko "jeden" model dla odniesienia, ale jest jeszcze jakaś magia, która może sprawić, że jeden model będzie wyglądał tak samo.

Przykład ogłoszenia:

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

i wyjście

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

Można również odkomentuj linię mongoose.set("debug",true) w aukcji, aby zobaczyć, jak mangusta faktycznie konstruowania połączeń.

To pokazuje, że można zastosować różne schematy do różnych obiektów pierwszej klasy, a nawet z różnymi metodami dołączonymi do nich, tak jak prawdziwe obiekty. Mongoose jest przechowywanie tych wszystkich w „pistolety” kolekcji z załączonym wzorem, i będzie zawierać wszystkie „rodzaje” refernced przez dyskryminatora:

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

Ale także każdy inny „typ” jest wymieniony z własnym modelu w specjalny sposób. Widzimy więc, że gdy mangusta przechowuje i odczytuje obiekt, pojawia się specjalne pole __t, które mówi mu, który "model" zastosować, a więc dołączony schemat.

Jako jeden przykład nazywamy metodę .shoot(), która jest zdefiniowana inaczej dla każdego modelu/schematu. Ponadto możesz nadal używać każdego jako modelu do zapytań lub innych operacji, ponieważ Ak47 automatycznie zastosuje wartość __t we wszystkich zapytaniach/podwyżkach.

Chociaż przechowywanie znajduje się w jednej kolekcji, może się wydawać, że ma wiele kolekcji, ale ma także tę zaletę, że pozwala je przechowywać w innych przydatnych operacjach. W ten sposób możesz zastosować rodzaj "polimorfizmu", którego szukasz.

+0

Wow, który był bardzo pouczający! Dziękuję Ci!! – BrentShanahan