Search code examples
mongodbmongoosemongoose-populate

Mongoose: Trying to use .virtual method to rename


I have to rename the name of the field when using populate.

const CategorySchema = new Schema(
  {
    name: {
      type: String,
      unique: true
    },
    featured: {
      type: Boolean,
      default: true
    },
    image: String,
    active: {
      type: Boolean,
      default: true
    },
    subCategoryIds: [{ type: Schema.Types.ObjectId, ref: 'SubCategory' }]
  },
  {
    timestamps: true
  }
);
export default mongoose.model('Category', CategorySchema);

This is my Category Schema.

And here is my SubCategory Schema

const SubCategory = new Schema(
  {
    name: {
      type: String,
      unique: true
    },
    active: {
      type: Boolean,
      default: true
    },
    categoryId: { type: Schema.Types.ObjectId, ref: 'Category' },
    productIds: [{ type: Schema.Types.ObjectId, ref: 'Product' }]
  },
  {
    timestamps: true
  }
);
SubCategory.virtual('category', {
  ref: 'Category',
  localField: 'categoryId',
  foreignField: '_id'
});
export default mongoose.model('SubCategory', SubCategory);

And here I have a filed categoryId, when using populate, I want it to be 'category', So I used virtual to create 'category`. and implemented this

const subCategories = await SubCategory.find({}).populate('category');

But unfortunately it isn't working, It returns the normal subCategory object and there is no category present. Am I missing something?


Solution

  • Why dont you use Mongodb aggregation pipeline, instead of using mongoose virtuals, You can use $lookup and change catergoryId to category while populating.

    Try this:

    const subCategories = await SubCategory.aggregate([{
        $lookup : {
            from : "categories",
            localField : "categoryId",
            foreginField : "_id",
            as : "category"
    },{
        $unwind : "$category"
    }])
    

    localField says which field to populate, from tells monogdb which collection to populate from, foreignField tells mongodb which field to match it for population, and as is used for the field in which result will be stored,

    $unwind is used in the next stage, because $lookup returns an array, we need to convert it to category object

    Read Mongodb $lookup documentation for more info.