skip to Main Content

I am using mongoose with Nextjs. If you look at the Review Schema below. It is linked with User schema and I am using the Review schema with populate in my React page to get the User document data, i-e; fullName.

Is there a way i can get types around the User document when populated inside Review?

I’ve tried (review?.user as User)?.fullName) which I’ve attached as well.

import { Document, InferSchemaType, Schema, model, models } from 'mongoose';

export const ReviewSchema = new Schema(
  {
    user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
    business: { type: Schema.Types.ObjectId, ref: 'Business', required: true },
    rating: { type: Number, required: true, min: 1, max: 5 },
    comment: { type: String, required: false },
    images: { type: [String], required: false },
  },
  {
    timestamps: true,
  },
);

export type Review = InferSchemaType<typeof ReviewSchema> & Document;

export const ReviewModel = models.Review || model('Review', ReviewSchema);

import { Document, InferSchemaType, Schema, model, models } from 'mongoose';

const UserSchema = new Schema({
  email: {
    type: String,
    unique: [true, 'Email already exists!'],
    required: [true, 'Email is required!'],
  },
  fullName: {
    type: String,
    required: [true, 'Fullname is required!'],
  },
  role: {
    type: String,
    enum: ['user', 'admin', 'owner'],
    default: 'user',
  },
  password: { type: String },
  image: { type: String },
  businesses: [{ type: Schema.Types.ObjectId, ref: 'Business' }],
});

export type User = InferSchemaType<typeof UserSchema> & Document;
export const UserModel = models.User || model('User', UserSchema);

Error Screen 1

Error screen 2

2

Answers


  1. user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
    

    change this field -> userId: { type: Schema.Types.ObjectId, ref: 'User', required: true }, and add new field user: { type: mongoose.Schema.Types.Mixed} and when you populate user for reviews, set {as: "user"} and then you can access user as entity.

    it is not best solution for your case…

    Login or Signup to reply.
  2. You should try defining User and Review as interfaces instead of using InferSchemaType as suggested in the docs. It might look like:

    import { Document, Schema, model, models } from 'mongoose';
    
    // export a Review interface
    export interface Review extends Document {
       user: Schema.Types.ObjectId; 
       business: Schema.Types.ObjectId;
       rating: number;
       comment?: string; //< optional? field in ReviewSchema
       images?: string[]; //< optional? field in ReviewSchema
       createdAt: Date; //< since you are using {timestamps: true} option
       updatedAt: Date; //< since you are using {timestamps: true} option
    }
    const ReviewSchema = new Schema<Review>({
       user: { 
          type: Schema.Types.ObjectId, 
          ref: 'User', 
          required: true 
       },
       business: { 
          type: Schema.Types.ObjectId, 
          ref: 'Business', 
          required: true 
       },
       rating: {
          type: Number, 
          required: true, 
          min: 1, 
          max: 5 
       },
       comment: { 
          type: String 
       },
       images: { 
          type: [String] 
       },
    }, { timestamps: true });
    
    export const ReviewModel = models.Review || model<Review>('Review', ReviewSchema);
    
    import { Document, Schema, model, models } from 'mongoose';
    
    // And a User interface
    export interface User extends Document {
       email: string;
       fullName: string;
       role: 'user' | 'admin' | 'owner';
       password?: string; //< optional? field in UserSchema
       image?: string; //< optional? field in UserSchema
       businesses: Schema.Types.ObjectId[];
    }
    
    const UserSchema = new Schema<User>({
       email: { 
          type: String, 
          unique: [true, 'Email already exists!'], 
          required: [true, 'Email is required!'] 
       },
       fullName: { 
          type: String, 
          required: [true, 'Fullname is required!'] 
       },
       role: { 
          type: String, 
          enum: ['user', 'admin', 'owner'], 
          default: 'user' 
       },
       password: { 
          type: String 
       },
       image: { 
          type: String 
       },
       businesses: [{ 
          type: Schema.Types.ObjectId, 
          ref: 'Business' 
       }],
    });
    
    export const UserModel = models.User || model<User>('User', UserSchema);
    

    Then when you populate:

    import { ReviewModel } from './path/to/review';
    import { User } from './path/to/user';
    
    const review = await ReviewModel.findOne({}).populate<{ user: User }>('user').exec();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search