mongodb-js / mongoose-autopopulate

Always populate() certain fields in your mongoose schemas
Apache License 2.0
222 stars 36 forks source link

Virtuals populate match works with object but not with function #112

Open A-Ghattas opened 1 year ago

A-Ghattas commented 1 year ago

When I use autopopulate to populate a virtual field that use the match option it works fine when I pass an object but doesn't work when I pass a function. The bug only appears when I use autopopulate. without the plugin, everything works fine.

const mongoose = require('mongoose');
const mongooseAutoPopulate =  require('mongoose-autopopulate');

const id = new mongoose.Types.ObjectId();
const subjectId = new mongoose.Types.ObjectId();

const teacherSchema = new mongoose.Schema({
    schoolClass: {type: mongoose.Schema.Types.ObjectId, ref: 'SchoolClass', autopopulate: { maxDepth: 2 },},
    schoolSubject: { type: mongoose.Schema.Types.ObjectId, ref: 'SchoolSubject', autopopulate: { maxDepth: 2 },},
  },
  {
    timestamps: true,
    toObject: { virtuals: true},
    toJSON: { virtuals: true},
    selectPopulatedPaths: false
  });

const lectureSchema = new mongoose.Schema({
  schoolClass: { type: mongoose.Schema.Types.ObjectId, ref: 'SchoolClass', autopopulate: { maxDepth: 2 },},
  schoolSubject: { type: mongoose.Schema.Types.ObjectId, ref: 'SchoolSubject', autopopulate: { maxDepth: 2 }, },
}, {
  timestamps: true,
  toObject: { virtuals: true },
  toJSON: { virtuals: true }
});

lectureSchema.virtual('assignedTeacher', {
  ref: 'Teacher',
  localField: 'schoolClass',
  foreignField: 'schoolClass',
  autopopulate: { maxDepth: 2 },
  match: (lecture) => ({
    schoolSubject: lecture.schoolSubject
  }),
  justOne: true
});

// If I replace the code above with this, it works fine
// lectureSchema.virtual('assignedTeacher', {
//   ref: 'Teacher',
//   localField: 'schoolClass',
//   foreignField: 'schoolClass',
//   autopopulate: { maxDepth: 2 },
//   match: {
//     schoolSubject: subjectId
//   },
//   justOne: true
// });

teacherSchema.plugin(mongooseAutoPopulate);
lectureSchema.plugin(mongooseAutoPopulate);

const classSchema = new mongoose.Schema({
  name: String
});
const subjectSchema = new mongoose.Schema({
  naem: String
});

const Teacher = mongoose.model('Teacher', teacherSchema);
const Lecture = mongoose.model('Lecture', lectureSchema);
const SchoolClass = mongoose.model('SchoolClass', classSchema);
const SchoolSubject = mongoose.model('SchoolSubject', subjectSchema);

async function run() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test-mongoose-bug');
  await mongoose.connection.dropDatabase();

  await SchoolClass.create({
    _id: id,
    name: 'MTH-101'
  });

  const sub = await SchoolSubject.create({
    _id: subjectId,
    name: 'Math'
  });

  await Teacher.create({
    schoolClass: id,
    schoolSubject: sub.id
  });

  const lecture = await Lecture.create({
    schoolClass: id,
    schoolSubject: sub.id
  });

  const data = await Lecture.findOne().populate('assignedTeacher');
  console.log(data, '///////', data.assignedTeacher)
}

run();
IslandRhythms commented 1 year ago
const mongoose = require('mongoose');
const mongooseAutoPopulate =  require('mongoose-autopopulate');

const id = new mongoose.Types.ObjectId();
const subjectId = new mongoose.Types.ObjectId();

const teacherSchema = new mongoose.Schema({
    schoolClass: {type: mongoose.Schema.Types.ObjectId, ref: 'SchoolClass', autopopulate: { maxDepth: 2 },},
    schoolSubject: { type: mongoose.Schema.Types.ObjectId, ref: 'SchoolSubject', autopopulate: { maxDepth: 2 },},
  },
  {
    timestamps: true,
    toObject: { virtuals: true},
    toJSON: { virtuals: true},
    selectPopulatedPaths: false
  });

const lectureSchema = new mongoose.Schema({
  schoolClass: { type: mongoose.Schema.Types.ObjectId, ref: 'SchoolClass', autopopulate: { maxDepth: 2 },},
  schoolSubject: { type: mongoose.Schema.Types.ObjectId, ref: 'SchoolSubject', autopopulate: { maxDepth: 2 }, },
}, {
  timestamps: true,
  toObject: { virtuals: true },
  toJSON: { virtuals: true }
});

lectureSchema.virtual('assignedTeacher', {
  ref: 'Teacher',
  localField: 'schoolClass',
  foreignField: 'schoolClass',
  autopopulate: { maxDepth: 2 },
  match: (lecture) => ({
    schoolSubject: lecture.schoolSubject
  }),
  justOne: true
});

// If I replace the code above with this, it works fine
/*
lectureSchema.virtual('assignedTeacher', {
  ref: 'Teacher',
  localField: 'schoolClass',
  foreignField: 'schoolClass',
  autopopulate: { maxDepth: 2 },
  match: {
    schoolSubject: subjectId
  },
  justOne: true
});
*/
teacherSchema.plugin(mongooseAutoPopulate);
lectureSchema.plugin(mongooseAutoPopulate);

const classSchema = new mongoose.Schema({
  name: String
});
const subjectSchema = new mongoose.Schema({
  name: String
});

const Teacher = mongoose.model('Teacher', teacherSchema);
const Lecture = mongoose.model('Lecture', lectureSchema);
const SchoolClass = mongoose.model('SchoolClass', classSchema);
const SchoolSubject = mongoose.model('SchoolSubject', subjectSchema);

async function run() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test-mongoose-bug');
  await mongoose.connection.dropDatabase();

  await SchoolClass.create({
    _id: id,
    name: 'MTH-101'
  });

  const sub = await SchoolSubject.create({
    _id: subjectId,
    name: 'Math'
  });

  await Teacher.create({
    schoolClass: id,
    schoolSubject: sub.id
  });

  const lecture = await Lecture.create({
    schoolClass: id,
    schoolSubject: sub.id
  });

  const data = await Lecture.findOne().populate('assignedTeacher');
  console.log(data, '///////', data.assignedTeacher)
}

run();