Sub document Inheritance

295 views
Skip to first unread message

Sam Martin

unread,
Feb 13, 2015, 6:29:53 AM2/13/15
to mongoo...@googlegroups.com
Hi all,

I have this model setup. I want a parent record with an array of sub docs. The sub docs have a schema, and use inheritance.


//
// child base model

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

    this.add({
        name: String
    });
};

util.inherits(abstractSchema, Schema);

var mySchema = new abstractSchema();

// 
// Inherited Types 

var textPropertySchema = new abstractSchema({
    length: Number
});

var numberPropertySchema = new abstractSchema({
    dp: Number
});

//
// Parent Model

var myModelSchema = mongoose.Schema({
    name: String,
    properties : [mySchema]   
});

When i save each an instance of numberPropertySchema or textPropertySchema, the _t (type is written) and is able to deserialise properly.

When however added as a sub doc array, they're all persisted with the base object properties only.

Is there any way round this? any extensions that could be used?

Coming from C#, the MongoDB driver lets you override (provide alternative) the serialisation/deserialisation of objects to and from the database.  Is this something that can easily be achieved using mongoose?

Thanks

Sam

Valeri Karpov

unread,
Feb 17, 2015, 2:50:52 PM2/17/15
to mongoo...@googlegroups.com
Hi,

I'm not sure I understand your question. The below script:

```
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var db = mongoose.createConnection('mongodb://localhost/OhMdDDi8_TM');
var util = require('util');

//
// child base model

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

    this.add({
        name: String
    });
};

util.inherits(abstractSchema, Schema);

var mySchema = new abstractSchema();

//
// Inherited Types

var textPropertySchema = new abstractSchema({
    length: Number
});

var numberPropertySchema = new abstractSchema({
    dp: Number
});

//
// Parent Model

var myModelSchema = mongoose.Schema({
    name: String,
    properties : [mySchema]
});

var Parent = db.model('Parent', myModelSchema, 'parents');

var p = new Parent({ name: 'test', properties: [{ name: 'x' }]});
p.save(function(err, p) {
  console.log(JSON.stringify(p));
});

```

Seems to work as expected for me. Looks like the name field gets added to the subdoc schema as expected. What specific issues are you having with this?

Sam Martin

unread,
Feb 23, 2015, 7:30:37 AM2/23/15
to mongoo...@googlegroups.com
I'm looking for the sub documents to carry the discriminator so they can be polymorphic.

i.e.

{
    name
: 'parent',
    properties
: [
       
{ name:'sub type 1',  __t : 'SubTypeOne', propertyOnlyInSubTypeOne: '1234' },
       
{ name: 'sub type 2', __t:'SubTypeTwo' , propertyOnlyInSubTypeTwo: 'abc'
   
]

}


When reconstructed into javascript objects, i'd like one parent object, with a array names properties, containing 1x SubTypeOne and 1x SubTypeTwo 

Does that make sense?

thanks
sam

Valeri Karpov

unread,
Feb 25, 2015, 3:23:00 PM2/25/15
to mongoo...@googlegroups.com
Discriminators don't quite make sense with subdocs as far as I know - if you don't have a model, you can't really have a discriminator. What are you trying to achieve with this polymorphic behavior?

Sam Martin

unread,
Feb 26, 2015, 8:00:16 AM2/26/15
to mongoo...@googlegroups.com
They do make sense, I've done something similar using C# driver, but didn't want to recreate the wheel when mongoose is already here... (and support inheritance albeit for only the parent document at moment from what i can see)

Consider this document:

{
    name
: "Sam",
    job
: "Carpenter",
    tools
: [
       
{ __t : "Hammer", length: 30, desc: "Normal hammer", weightKg: 0.5 },
       
{ __t: "Screwdriver", type: "Flat", desc: "Flat headed screwdriver", weightKg: 0.15}
   
]
}


//
// child base model

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

   
this.add({
        weightKg
: Number,
        desc
: String
   
}
}

util
.inherits(baseToolSchema, Schema);

var myBaseToolSchema = new baseToolSchema();

//
// Tool (inherited) Types

var screwdriverType= new baseToolSchema({
    type
: String
});

var hammerType= new baseToolSchema({
    length
: Number
});

//
// Worker Model

var workerSchema = mongoose.Schema({
    name
: String,
    job
: String,
    tools
: [myBaseToolSchema]  
});

When the document is deserialised from the database, i wand the array of tools to each have an instance of the their respective tool objects.

i.e.

tools : [ hammerType, screwdriverType]


not

tools : [baseToolSchema,baseToolSchema]


Does that make sense?

Valeri Karpov

unread,
Feb 28, 2015, 11:37:02 AM2/28/15
to mongoo...@googlegroups.com
I agree, this feature would be excellent. My "not making sense" comment was referring to the fact that this is incompatible with how discriminators currently work. To get this to work, you would have to have a model for BaseSchema and discriminators for "Hammer" and "Screwdriver", which isn't quite how mongoose nested schemas work - nested schemas are schemas that don't necessarily have a model. It could be made to work, but right now it won't work at all. I opened up a Github issue to track this suggestion here: https://github.com/LearnBoost/mongoose/issues/2723
Reply all
Reply to author
Forward
0 new messages