diff --git a/index.d.ts b/index.d.ts index ff40c1963aa..50ba645b3fc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -603,8 +603,8 @@ declare module 'mongoose' { interface AcceptsDiscriminator { /** Adds a discriminator type. */ - discriminator(name: string | number, schema: Schema, value?: string): Model; - discriminator>(name: string | number, schema: Schema, value?: string): U; + discriminator(name: string | number, schema: Schema, value?: string | number | ObjectId): Model; + discriminator>(name: string | number, schema: Schema, value?: string | number | ObjectId): U; } interface AnyObject { [k: string]: any } diff --git a/lib/helpers/discriminator/areDiscriminatorValuesEqual.js b/lib/helpers/discriminator/areDiscriminatorValuesEqual.js new file mode 100644 index 00000000000..87b2408e6db --- /dev/null +++ b/lib/helpers/discriminator/areDiscriminatorValuesEqual.js @@ -0,0 +1,16 @@ +'use strict'; + +const ObjectId = require('../../types/objectid'); + +module.exports = function areDiscriminatorValuesEqual(a, b) { + if (typeof a === 'string' && typeof b === 'string') { + return a === b; + } + if (typeof a === 'number' && typeof b === 'number') { + return a === b; + } + if (a instanceof ObjectId && b instanceof ObjectId) { + return a.toString() === b.toString(); + } + return false; +}; \ No newline at end of file diff --git a/lib/helpers/discriminator/getDiscriminatorByValue.js b/lib/helpers/discriminator/getDiscriminatorByValue.js index a107a910492..741fb8cd02f 100644 --- a/lib/helpers/discriminator/getDiscriminatorByValue.js +++ b/lib/helpers/discriminator/getDiscriminatorByValue.js @@ -1,5 +1,7 @@ 'use strict'; +const areDiscriminatorValuesEqual = require('./areDiscriminatorValuesEqual'); + /*! * returns discriminator by discriminatorMapping.value * @@ -8,20 +10,18 @@ */ module.exports = function getDiscriminatorByValue(model, value) { - let discriminator = null; if (!model.discriminators) { - return discriminator; + return null; } for (const name in model.discriminators) { const it = model.discriminators[name]; if ( it.schema && it.schema.discriminatorMapping && - it.schema.discriminatorMapping.value == value + areDiscriminatorValuesEqual(it.schema.discriminatorMapping.value, value) ) { - discriminator = it; - break; + return it; } } - return discriminator; + return null; }; \ No newline at end of file diff --git a/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js b/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js index f3e71a093a9..b29fb6521e1 100644 --- a/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +++ b/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js @@ -1,5 +1,7 @@ 'use strict'; +const areDiscriminatorValuesEqual = require('./areDiscriminatorValuesEqual'); + /*! * returns discriminator by discriminatorMapping.value * @@ -16,7 +18,7 @@ module.exports = function getSchemaDiscriminatorByValue(schema, value) { if (discriminatorSchema.discriminatorMapping == null) { continue; } - if (discriminatorSchema.discriminatorMapping.value === value) { + if (areDiscriminatorValuesEqual(discriminatorSchema.discriminatorMapping.value, value)) { return discriminatorSchema; } } diff --git a/lib/helpers/model/discriminator.js b/lib/helpers/model/discriminator.js index 2ad4c5e3754..455d17de2f9 100644 --- a/lib/helpers/model/discriminator.js +++ b/lib/helpers/model/discriminator.js @@ -1,6 +1,7 @@ 'use strict'; const Mixed = require('../../schema/mixed'); +const ObjectId = require('../../types/objectid'); const defineKey = require('../document/compile').defineKey; const get = require('../get'); const utils = require('../../utils'); @@ -63,7 +64,9 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu } let value = name; - if (typeof tiedValue == 'string' && tiedValue.length) { + if ((typeof tiedValue === 'string' && tiedValue.length) || + typeof tiedValue === 'number' || + tiedValue instanceof ObjectId) { value = tiedValue; } diff --git a/test/model.discriminator.test.js b/test/model.discriminator.test.js index 2465826fbe6..18ea0f91317 100644 --- a/test/model.discriminator.test.js +++ b/test/model.discriminator.test.js @@ -1094,6 +1094,35 @@ describe('model', function() { }); }); + it('supports ObjectId as tied value (gh-10130)', function() { + const eventSchema = new Schema({ message: String, kind: 'ObjectId' }, + { discriminatorKey: 'kind' }); + + const Event = db.model('Event', eventSchema); + const clickedId = new mongoose.Types.ObjectId(); + const purchasedId = new mongoose.Types.ObjectId(); + Event.discriminator('Clicked', new Schema({ + element: String + }), clickedId); + Event.discriminator('Purchased', new Schema({ + product: String + }), purchasedId); + + return co(function*() { + yield Event.create([ + { message: 'test', element: '#buy', kind: clickedId }, + { message: 'test2', product: 'Turbo Man', kind: purchasedId } + ]); + + const docs = yield Event.find().sort({ message: 1 }); + assert.equal(docs.length, 2); + assert.equal(docs[0].kind.toHexString(), clickedId.toHexString()); + assert.equal(docs[0].element, '#buy'); + assert.equal(docs[1].kind.toHexString(), purchasedId.toHexString()); + assert.equal(docs[1].product, 'Turbo Man'); + }); + }); + it('Embedded discriminators in nested doc arrays (gh-6202)', function() { const eventSchema = new Schema({ message: String }, { discriminatorKey: 'kind',