Search code examples
node.jsmongodbmongoosemongoose-schemamongoose-populate

populate subdocument in mongoose


I hope someone can help me with this issue. I am trying to populate a subSchema but I have no luck. I have a replySchema, commentSchema and a UserSchema. replySchema is subDocument to commentSchema and I want to populate both of them with user's details from userSchema My issue is that with the code below it does not populate my replySchema:

REPLY-SCHEMA and COMMENT-SCHEMA

const replySchema = new mongoose.Schema(
  {
    replyComment: {
      type: String,
      required: [true, 'Reply comment cannot be empty'],
    },
    createdAt: {
      type: Date,
      default: Date.now(),
    },
    user: {
      type: mongoose.Schema.ObjectId,
      ref: 'User',
      required: [true, 'Comment must belong to a user'],
    },
  },
  {
    timestamps: true,
  }
);

const commentSchema = new mongoose.Schema(
  {
    comment: {
      type: String,
      required: [true, 'Comment cannot be empty'],
    },
    createdAt: {
      type: Date,
      default: Date.now(),
    },
    // createdAt: Number,
    // updatedAt: Number,
    post: {
      type: mongoose.Schema.ObjectId,
      ref: 'Post',
      required: [true, 'Comment must belong to a Post'],
    },
    user: {
      type: mongoose.Schema.ObjectId,
      ref: 'User',
      required: [true, 'Comment must belong to a user'],
    },
    replies: [replySchema], //replySchema sub-document - is this the right way?
  },
  {
    // timestamps: { currentTime: () => Math.floor(Date.now() / 1000) },
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

replySchema.pre(/^find/, function (next) {
  this.populate({
    path: 'user',
    select: 'name role avatar',
  });
  next();
});

commentSchema.pre(/^find/, function (next) {
  this.populate({
    path: 'user',
    select: 'name role avatar',
  });
  next();
});

const Comment = mongoose.model('Comment', commentSchema);

module.exports = Comment;

USER-SCHEMA

const userSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      trim: true,
      required: [true, 'Please insert your name'],
    },

    avatar: {
      type: Object,
    },

    role: {
      type: String,
      enum: ['user', 'admin'],
      default: 'user',
    },

  },
  {
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

const User = mongoose.model('User', userSchema);

module.exports = User;

Thank you very much for your time!


Solution

  • To populate user's data in replies:

    this.populate([
        'user', // To populate commentSchema's user field
        {
            path: 'replies',
            populate: 'user'
        } // To populate replySchema's user field
    ]);
    

    Edit:

    To populate specific fields:

    this.populate([
        {
            path: 'user',
            select: 'name role avatar'
        },
        {
            path: 'replies',
            populate: {
                path: 'user',
                select: 'name role avatar'
            }
        }
    ]);