Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finding discriminators should select correct model #6701

Closed
roblevy opened this issue Jul 9, 2018 · 6 comments
Closed

Finding discriminators should select correct model #6701

roblevy opened this issue Jul 9, 2018 · 6 comments
Labels
enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature

Comments

@roblevy
Copy link

roblevy commented Jul 9, 2018

I want to request a feature.

Models should 'know' about their discriminator children, and select the correct schema when running ParentModel.find().

In the following example, Membership can be of two discriminator types, Subscription and Ticket.

Each of these discriminators has different gets, as follows:

const membershipSchema = mongoose.Schema({
  name: { type: String, required: true },
  price: { type: Number, required: true, get: p => `£${p}.00` }
}, { discriminatorKey: 'type' });

const subscriptionSchema = mongoose.Schema({
  frequency: {
    type: String, enum: [ 'week' , 'month' ],
    required: true, get: val => `${val}ly subscription` }
})

const ticketSchema = mongoose.Schema({
  frequency: { type: String, default: 'one-off' }
});

const Membership = mongoose.model('Membership', membershipSchema);
const Subscription = Membership.discriminator('Subscription', subscriptionSchema);
const Ticket = Membership.discriminator('Ticket', ticketSchema);

Currently, if I find all the Memberships, the frequency getter for a Subscription is not run.

Instead I get an object like:

{ __t: 'Subscription', name: 'Monthly subscription', price: '£1.00', frequency: 'month' }

This happens because the documents are returned with membershipSchema not with subscriptionSchema.

But given that the __t field is correctly being set to "Subscription", it seems reasonable that Mongoose would find the correct schema and apply it.

node version: v9.10.0, mongoose version 5.2.0.


Here is a possible test:

Promise.all([
  Subscription.create({ name: 'Monthly subscription', price: 1, frequency: 'month'}),
  Ticket.create({ name: 'Ticket', price: 2 })
]).then(() => {
  Membership.find({ price: 1 })
    .then(subscription => {
      assert.equal(subscription, 'monthly subscription');
    });
  Membership.find({ price: 2 })
    .then(ticket => {
      assert.equal(ticket, 'one-off');
    });
});
@roblevy
Copy link
Author

roblevy commented Jul 9, 2018

@roblevy
Copy link
Author

roblevy commented Jul 9, 2018

I've come up with a reasonably compact way of doing this, as long as none of the documents are stored under the parent model:

const discriminators = ParentModel.discriminators;

return Promise.all(Object.keys(discriminators).map(i => discriminators[i].find({ course: this._id }))
).then(promiseResults =>
  promiseResults.reduce((arr, el) => arr.concat(el), [])
);

@vkarpov15 vkarpov15 added this to the 5.3 milestone Jul 13, 2018
@vkarpov15 vkarpov15 added the enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature label Jul 13, 2018
@vkarpov15
Copy link
Collaborator

Thanks for reporting, will fix this 👍

@vkarpov15 vkarpov15 modified the milestones: 5.3, 5.x Unprioritized Sep 16, 2018
@maloguertin
Copy link

Is this in the plans anymore? I think this is really important especially people who wants to introduce Discriminators later into their development process.

@vkarpov15
Copy link
Collaborator

This looks fixed in 5.5.x, I believe this was fixed in 5.4.20 with #7586. The below script works for me, so I'm going to close this for now. @maloguertin can you confirm your version of Mongoose?

const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);

const GITHUB_ISSUE = `gh6701`;
const connectionString = `mongodb://localhost:27017/${ GITHUB_ISSUE }`;
const { Schema } = mongoose;

run().then(() => console.log('done')).catch(error => console.error(error.stack));

async function run() {
  await mongoose.connect(connectionString);
  await mongoose.connection.dropDatabase();

  const membershipSchema = mongoose.Schema({
  name: { type: String, required: true },
  price: { type: Number, required: true, get: p => ${p}.00` }
}, { discriminatorKey: 'type' });

const subscriptionSchema = mongoose.Schema({
  frequency: {
    type: String, enum: [ 'week' , 'month' ],
    required: true, get: val => `${val}ly subscription` }
})

const ticketSchema = mongoose.Schema({
  frequency: { type: String, default: 'one-off' }
});

const Membership = mongoose.model('Membership', membershipSchema);
const Subscription = Membership.discriminator('Subscription', subscriptionSchema);
const Ticket = Membership.discriminator('Ticket', ticketSchema);

  await Subscription.create({ name: 'Monthly subscription', price: 1, frequency: 'month'});
  await Ticket.create({ name: 'Ticket', price: 2 });

  const sub = await Membership.findOne({ price: 1 });

  console.log(sub);
  console.log(sub.frequency); // "monthly subscription"
}

@vkarpov15 vkarpov15 removed this from the 5.x Unprioritized milestone Jul 21, 2019
@maloguertin
Copy link

@vkarpov15 everything works fine, I'm sorry one of my model had the discriminator key defined in a child schema instead of the parent schema.

@Automattic Automattic locked as resolved and limited conversation to collaborators Jul 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature
Projects
None yet
Development

No branches or pull requests

3 participants