Apa yang Anda cari di sini adalah .discriminator()
mon luwak metode. Ini pada dasarnya memungkinkan Anda untuk menyimpan objek dari tipe yang berbeda dalam koleksi yang sama, tetapi menjadikannya sebagai objek kelas satu yang dapat dibedakan.
Perhatikan bahwa prinsip "koleksi yang sama" di sini penting untuk bagaimana .populate()
karya dan definisi referensi dalam model yang berisi. Karena Anda benar-benar hanya dapat menunjuk ke "satu" model untuk referensi, tetapi ada beberapa keajaiban lain yang dapat membuat satu model muncul sebanyak mungkin.
Contoh daftar:
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();
}
);
Dan keluaran
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"
}
]
Anda juga dapat menghapus komentar mongoose.set("debug",true)
baris dalam daftar untuk melihat bagaimana luwak sebenarnya membuat panggilan.
Jadi apa yang ditunjukkan ini adalah bahwa Anda dapat menerapkan skema yang berbeda ke objek kelas satu yang berbeda, dan bahkan dengan metode berbeda yang melekat padanya seperti objek nyata. Luwak menyimpan semua ini dalam koleksi "senjata" dengan model terlampir, dan itu akan berisi semua "jenis" yang dirujuk oleh pembeda:
var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );
Tetapi juga setiap "tipe" yang berbeda direferensikan dengan modelnya sendiri dengan cara yang khusus. Jadi Anda melihat bahwa ketika luwak menyimpan dan membaca objek, ada __t
khusus bidang yang memberi tahu "model" mana yang akan diterapkan, dan karenanya skema terlampir.
Sebagai salah satu contoh kita memanggil .shoot()
metode, yang didefinisikan berbeda untuk setiap model/skema. Dan Anda juga masih dapat menggunakan masing-masing sebagai model dengan sendirinya untuk kueri atau operasi lainnya, karena Ak47
akan secara otomatis menerapkan __t
nilai di semua kueri/pembaruan.
Jadi, meskipun penyimpanan dalam satu koleksi, itu bisa tampak seperti banyak koleksi, tetapi juga memiliki manfaat untuk menyatukannya untuk operasi berguna lainnya. Ini adalah bagaimana Anda dapat menerapkan jenis "polimorfisme" yang Anda cari.