Những gì bạn đang tìm kiếm ở đây là mongoose .discriminator()
phương pháp. Về cơ bản, điều này cho phép bạn lưu trữ các đối tượng thuộc các loại khác nhau trong cùng một bộ sưu tập, nhưng có chúng dưới dạng các đối tượng hạng nhất có thể phân biệt được.
Lưu ý rằng nguyên tắc "cùng một bộ sưu tập" ở đây rất quan trọng đối với cách .populate()
hoạt động và định nghĩa của tham chiếu trong mô hình chứa. Vì bạn thực sự chỉ có thể trỏ đến "một" mô hình để tham khảo, nhưng có một số phép thuật khác có thể làm cho một mô hình xuất hiện nhiều.
Danh sách ví dụ:
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();
}
);
Và đầu ra
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"
}
]
Bạn cũng có thể bỏ ghi chú mongoose.set("debug",true)
trong danh sách để xem cách mongoose thực sự tạo ra các lệnh gọi.
Vì vậy, điều này chứng tỏ rằng bạn có thể áp dụng các lược đồ khác nhau cho các đối tượng lớp đầu tiên khác nhau và thậm chí với các phương thức khác nhau được gắn vào chúng giống như các đối tượng thực. Mongoose đang lưu trữ tất cả những thứ này trong bộ sưu tập "súng" với mô hình đính kèm và nó sẽ chứa tất cả "loại" được tham chiếu bởi người phân biệt:
var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );
Nhưng mỗi "loại" khác nhau được tham chiếu với mô hình riêng của nó theo một cách đặc biệt. Vì vậy, bạn thấy rằng khi mongoose lưu trữ và đọc đối tượng, có một __t
đặc biệt trường cho nó biết "mô hình" nào cần áp dụng và do đó, lược đồ được đính kèm.
Như một ví dụ mà chúng tôi gọi là .shoot()
, được định nghĩa khác nhau cho từng mô hình / lược đồ. Và bạn vẫn có thể sử dụng từng thứ làm mô hình cho chính nó cho các truy vấn hoặc các hoạt động khác, vì Ak47
sẽ tự động áp dụng __t
giá trị trong tất cả các truy vấn / upates.
Vì vậy, mặc dù bộ lưu trữ nằm trong một bộ sưu tập, nó có thể có vẻ là nhiều bộ sưu tập, nhưng cũng có lợi ích là giữ chúng lại với nhau cho các hoạt động hữu ích khác. Đây là cách bạn có thể áp dụng loại "đa hình" mà bạn đang tìm kiếm.