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

.find().populate() fails due to discriminator value not matching the model's name #8324

Closed
ghost opened this issue Nov 11, 2019 · 2 comments
Closed
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@ghost
Copy link

ghost commented Nov 11, 2019

Do you want to request a feature or report a bug?
bug

What is the current behavior?
When using .find().populate() it fails on a virtual field.
This is caused due to the .find() being executed on a discriminated model for which the registered value is different then the ModelName.

fail:
const items = await main.find().populate('virtualField').exec();
--> items.virtualField is not correct.

success:
const items = await main.find().exec();
await main.populate('virtualField').execPopulate();
--> items.virtualField is correct.

If the current behavior is a bug, please provide the steps to reproduce.
The following (simplified code) fails with a MongooseError due to model "discriminatedValue" not being registered on the following line:
https://github.com/Automattic/mongoose/blob/master/lib/helpers/populate/getModelsMapForPopulate.js#L305

let mainSchema = new Schema(
  {
    title: { type: String },
  },
  {
    discriminatorKey: 'type',
  }
);

mainSchema.virtual('virtualField', {
  ref: 'AnotherModel',
  localField: '_id',
  foreignField: 'main',
});

let discriminatedSchema = new Schema({
  {
    description: { type: String },
  }
});

let main = connection.model('Main', mainSchema, 'main');
let discriminated = this.main.discriminator('Discriminated', discriminatedSchema, 'discriminatedValue');

const items = await main.find().populate('virtualField').exec();

The code works after changing the code to the following (where the discriminator is retrieved by going from the value to the model).

modelForFindSchema = utils.getValue(discriminatorKey, doc);
if (modelForFindSchema) {
  const discriminatorByValue = getDiscriminatorByValue(model, modelForFindSchema);
  if (discriminatorByValue !== null) {
    modelForCurrentDoc = discriminatorByValue;
  } else {
    try {
      modelForCurrentDoc = model.db.model(modelForFindSchema);
    } catch (error) {
      return error;
    }
  }
  
  ...

What is the expected behavior?
That the populate works by correctly identifying the associated model within the .find

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Node.js: v12.11.1
MongoDB: v3.4.10
Mongoose: v5.7.9

@vkarpov15 vkarpov15 added this to the 5.7.12 milestone Nov 14, 2019
@vkarpov15 vkarpov15 added the needs repro script Maybe a bug, but no repro script. The issue reporter should create a script that demos the issue label Nov 14, 2019
@ghost
Copy link
Author

ghost commented Nov 18, 2019

Below is a test script which fails. When the value "triggerValue" is removed as the defined value for the discriminator the test passes.

'use strict';

const start = require('./common');
const assert = require('assert');

const mongoose = start.mongoose;
const Schema = mongoose.Schema;
const ObjectId = Schema.ObjectId;

const BookSchema = new Schema({
  title: String,
}, {
  discriminatorKey: 'type',
  toJSON: {
    virtuals: true,
  }
});

BookSchema.virtual('authors', {
  ref: 'Author',
  localField: '_id',
  foreignField: 'book',
});

const ThrillerSchema = new Schema({
  description: String,
});

const AuthorSchema = new Schema({
  name: String,
  book: ObjectId,
});

describe.only('issue-8324', function() {
  let db, Book, Thriller, Author;

  before(function(done) {
    db = start();

    Book = db.model('Book', BookSchema);
    Thriller = Book.discriminator('Thriller', ThrillerSchema, 'triggerValue');
    Author = db.model('Author', AuthorSchema);

    Thriller.create({
      title: 'Thriller 1',
      description: 'Very nice book',
    }, function(err, thriller1) {
      assert.ifError(err);

      Author.create({
        name: 'Author 1',
        book: thriller1
      }, function(err) {
        assert.ifError(err);

        done();
      });
    });
  });

  after(function(done) {
    db.close(done);
  });

  it('Should populate the authors virtual', function(done) {
    Book
      .findOne()
      .populate('authors')
      .exec(function(err, book) {
        assert.ifError(err);

        console.log(JSON.stringify(book));

        assert(book.authors);
        assert.equal(book.authors.length, 1);
        done();
      });
  });
});

vkarpov15 added a commit that referenced this issue Nov 19, 2019
@vkarpov15 vkarpov15 added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. and removed needs repro script Maybe a bug, but no repro script. The issue reporter should create a script that demos the issue labels Nov 19, 2019
@vkarpov15
Copy link
Collaborator

Thanks for the detailed repro, fix will be in v5.7.12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
Development

No branches or pull requests

1 participant