Note that there are some explanatory texts on larger screens.

plurals
  1. POMongoose schema inheritance and model populate
    primarykey
    data
    text
    <p>I have been trying this with the built in inheritance features of mongoose (rather than the extend plugin) but haven't been having much luck so far. This is a simplified example of code I am trying to use which exhibits the same problem. This is based on an expanded version of the mongoose documentation for schema inheritance using discriminators - <a href="http://mongoosejs.com/docs/api.html#model_Model.discriminator">http://mongoosejs.com/docs/api.html#model_Model.discriminator</a></p> <pre><code>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); </code></pre> <p>Example code to add the documents:</p> <pre><code>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); </code></pre> <p>So when finding a record <strong>without</strong> populate:</p> <pre><code>Person .findOne({ name: 'Billy' }) .exec(callback); </code></pre> <p>The result is as expected, the bossStatus refers to an _id from the bossstatuses collection:</p> <pre><code>null { name: 'Billy', bossStatus: 52a20ab0185a7f4530000001, _id: 52a20ab0185a7f4530000004, __v: 0, __t: 'Boss' } </code></pre> <p>When adding the populate call:</p> <pre><code>Person .findOne({ name: 'Billy' }) .populate('bossStatus') .exec(callback); </code></pre> <p>The resulting bossStatus property of the Person result is <strong>null</strong>:</p> <pre><code>null { name: 'Billy', bossStatus: null, _id: 52a20ab0185a7f4530000004, __v: 0, __t: 'Boss' } </code></pre> <p>EDIT:</p> <p>Ok I've just put together what is probably a better example of what I'm trying to achieve, the schema structure lends itself more to a relational DB but hopefully makes the problem clearer.</p> <pre><code>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); </code></pre> <p>The LocalDevice and RemoteDevice schemas could (and probably would) include other differences.. The switch would for example use a DeviceFactory or something to create the instances. My thinking was it should be possible to search the devices table for a device by 'name' and populate the collection references (if this is the correct terminology?) without having to specify the collection to search in - this was my understanding of the point of schema inheritance - or have I completely misunderstood?</p> <p>Thanks for replies so far!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload