簡體   English   中英

Mongoose模式繼承和模型填充

[英]Mongoose schema inheritance and model populate

我一直在嘗試使用mongoose的內置繼承功能(而不是擴展插件)但到目前為止還沒有太多運氣。 這是我嘗試使用的代碼的簡化示例,它表現出相同的問題。 這是基於使用鑒別器的模式繼承的mongoose文檔的擴展版本 - http://mongoosejs.com/docs/api.html#model_Model.discriminator

var util = require('util');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/problem');

var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;

function BaseSchema() {
  Schema.apply(this, arguments);

  this.add({
    name: String,
    createdAt: Date
  });
}
util.inherits(BaseSchema, Schema);


var BossStatusSchema = new Schema({
  status: String
});
var BossStatus = mongoose.model('BossStatus', BossStatusSchema);

var PersonSchema = new BaseSchema();
var Person = mongoose.model('Person', PersonSchema);

var BossSchema = new BaseSchema({
  department: String,
  bossStatus: {
    type: ObjectId,
    ref: 'BossStatus'
  }
});
var Boss = Person.discriminator('Boss', BossSchema);

添加文檔的示例代碼:

var superBoss = new BossStatus({
  status: 'super'
});
var normalBoss = new BossStatus({
  status: 'normal'
});
var andy = new Person({
  name: 'Andy'
});
var billy = new Boss({
  name: 'Billy',
  bossStatus: superBoss._id
});

var callback = function(err, result) {
  console.dir(err);
  console.dir(result);
};

superBoss.save(callback);
normalBoss.save(callback);
andy.save(callback);
billy.save(callback);

所以當找到沒有填充的記錄時:

Person
.findOne({
  name: 'Billy'
})
.exec(callback);

結果如預期的那樣,bossStatus引用了來自bossstatuses集合的_id:

null
{ name: 'Billy',
  bossStatus: 52a20ab0185a7f4530000001,
  _id: 52a20ab0185a7f4530000004,
  __v: 0,
  __t: 'Boss' }

添加填充調用時:

Person
.findOne({
  name: 'Billy'
})
.populate('bossStatus')
.exec(callback);

Person結果的最終bossStatus屬性為null

null
{ name: 'Billy',
  bossStatus: null,
  _id: 52a20ab0185a7f4530000004,
  __v: 0,
  __t: 'Boss' }

編輯:

好吧,我剛剛把可能是我想要實現的更好的例子放在一起,模式結構更適合於關系數據庫,但希望能使問題更加清晰。

var util = require('util');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/problem');

var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;

function BaseSchema() {
  Schema.apply(this, arguments);

  this.add({
    name: {
      type: String,
      unique: true,
      required: true
    }
  });
}
util.inherits(BaseSchema, Schema);

var DeviceSchema = new BaseSchema();
var LocalDeviceSchema = new BaseSchema({
  driver: {
    type: ObjectId,
    ref: 'Driver'
  }
});
var RemoteDeviceSchema = new BaseSchema({
  networkAddress: {
    type: ObjectId,
    ref: 'NetworkAddress'
  }
});

var DriverSchema = new Schema({
  name: {
    type: String,
    unique: true,
    required: true
  }
});

var NetworkHostSchema = new Schema({
  host: {
    type: String,
    unique: true,
    required: true
  }
});

var NetworkAddressSchema = new Schema({
  networkHost: {
    type: ObjectId,
    ref: 'NetworkHost'
  },
  port: {
    type: Number,
    min: 1,
    max: 65535
  }
});

var Driver = mongoose.model('Driver', DriverSchema);
var NetworkHost = mongoose.model('NetworkHost', NetworkHostSchema);
var NetworkAddress = mongoose.model('NetworkAddress', NetworkAddressSchema);

var Device = mongoose.model('Device', DeviceSchema);
var LocalDevice = Device.discriminator('LocalDevice', LocalDeviceSchema);
var RemoteDevice = Device.discriminator('RemoteDevice', RemoteDeviceSchema);

var networkHost = new NetworkHost({
  host: '192.168.2.1'
});

var networkAddress = new NetworkAddress({
  networkHost: networkHost._id,
  port: 3000
});

var remoteDevice = new RemoteDevice({
  name: 'myRemoteDevice',
  networkAddress: networkAddress._id
});


var driver = new Driver({
  name: 'ftdi'
});

var localDevice = new LocalDevice({
  name: 'myLocalDevice',
  driver: driver._id
});


var callback = function(err, result) {
  if(err) {
    console.log(err);
  }
  console.dir(result);
};

/*
// Uncomment to save documents

networkHost.save(function() {
  networkAddress.save(function() {
    remoteDevice.save(callback);
  });
});

driver.save(function() {
  localDevice.save(callback);
});
*/

var deviceCallback = function(err, device) {
  if(err) {
    console.log(err);
  }
  switch(device.__t) {
    case 'LocalDevice':
      console.log('Would create a local device instance passing populated result');
      break;
    case 'RemoteDevice':
      console.log('Would create a remote device instance passing populated result');
      break;
  }
};

Device
.findOne({name: 'myLocalDevice'})
.populate('driver')
.exec(deviceCallback);

LocalDevice和RemoteDevice模式可能(並且可能會)包含其他差異。例如,交換機將使用DeviceFactory或其他東西來創建實例。 我的想法是應該可以通過'name'在設備表中搜索設備並填充集合引用(如果這是正確的術語?)而不必指定要搜索的集合 - 這是我對點的理解架構繼承 - 還是我完全被誤解了?

感謝您的回復!

你正在尋找一個老板,而不是一個人:

Boss
.findOne({
  name: 'Billy'
})
.populate('bossStatus')
.exec(callback);

看起來像個bug。 在調試處於活動狀態時,這是針對填充查詢顯示的內容:

 Mongoose: people.findOne({ name: 'Billy' }) { fields: undefined } Mongoose: people.find({ _id: { '$in': [ ObjectId("52a221ee639cc03d71000001") ] } }) { fields: undefined } 

(顯示的ObjectId是存儲在bossStatusObjectId

所以Mongoose正在查詢錯誤的集合( people而不是bossstatuses )。

正如@regretoverflow指出的那樣,如果你正在尋找老板,請使用Boss模型而不是Person模型。

如果您確實希望通過Person模型填充bossStatus ,則可以顯式聲明需要搜索填充的模型:

 .populate({ path : 'bossStatus', model : 'BossStatus' }) // or shorter but less clear: // .populate('bossStatus', {}, 'BossStatus') 

編輯:(使用您的Device示例)

driverLocalDeviceSchema一部分,但是你要查詢Device模型,它沒有driver概念,並且在Device實例的上下文中填充driver對Mongoose沒有意義。

填充每個實例的另一種可能性是在檢索文檔后執行此操作。 你已經有了deviceCallback功能,這可能會起作用:

 var deviceCallback = function(err, device) { if(err) { console.log(err); } switch(device.__t) { // or `device.constructor.modelName` case 'LocalDevice': device.populate('driver', ...); break; case 'RemoteDevice': device.populate('networkAddress', ...); break; } }; 

原因是該文檔已經被轉換為正確的模型,當您使用find populate時,顯然不會發生這種情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM