Skip to content

Instantly share code, notes, and snippets.

@christarnowski
Created October 25, 2012 19:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save christarnowski/3954978 to your computer and use it in GitHub Desktop.
Save christarnowski/3954978 to your computer and use it in GitHub Desktop.
Mongoose Polymorphic Schemas API design document

@hitsthings Your API is worth considering, without a doubt. My remarks:

  • It introduces new entities/method, which is not a big deal, but should be avoided if possible.
  • Does not support multiple parent schemas ("classes"). The latter of course can be easily fixed by using an array instead of a String value for _type(s).
  • I like that you're able to chose the property that holds the type information.
  • I think parent properties should be included by default, which is in line with programmers intuition.

I came up with an alternative approach that keeps the changes to the current API to a bare minimum and leverages the way models are created and cached.

Alternative approach

This feature will require that a special top-level array property _types is added to each document whose model belongs to an inheritance chain. Additionally, the order of elements in the array will denote an inheritance order, albeit in reverse. This implies that the first element of the array will specify the model that should be used when parsing the document's JSON.

For example, given ModelA, ModelB and ModelC, if ModelB extends ModelA, the actual documents will look as follows:

  • ModelA: {_id: ObjectId('1'), _types: ['ModelA']}
  • ModelB: {_id: ObjectId('2'), _types: ['ModelB', 'ModelA']}
  • ModelC: {_id: ObjectId('3')}

To define such relation between models, one will have to pass to the mongoose.model function an array that specifies an inheritance order. The array should include only top-most model names, i.e. if ModelC inherits from ModelB which in turn inherits from ModelA, only ModelB should be included in the array. Mongoose will automatically add intermediate models, while preserving the inheritance order.

Below snippet illustrates basic usage of the model/schema inheritance:

var Schema = mongoose.Schema,
    model = mongoose.model;

var PersonSchema = new Schema({name: String}),
    EmployeeSchema = new Schema({joined: Number}),
    HasGitHubAccountSchema = new Schema({github_account: String}),
    ProgrammerSchema = new Schema({skills: [String]});

var Person = model('Person', PersonSchema, 'people'),
    Employee = model('Employee', EmployeeSchema, 'people', ['Person']), // _types: ['Employee', 'Person']
    HasGitHubAccount = model('HasGitHubAccount', HasGitHubAccountSchema, 'people'),
    ProgrammerSchema = model('Programmer', ProgrammerSchema, 'people', ['Employee', 'HasGitHubAccount']); // _types: ['Programmer', 'Employee', 'Person', 'HasGitHubAccount']

// At this point:
// Person documents will have {_types: ['Person']}
// HasGitHubAccount documents will have {_types: ['HasGitHubAccount']}

Note that the order in which models are created matters. Parent models should be defined before all child models.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment