typescriptmongoosetypescript-typingsmongoose-populate

Trying to use 'ref' in typescript schema models giving error without property '' does not exist on type 'ObjectId' error


Below is part of my code . I am coming from js to typescript. Trying to convert my existing js code to typescript. I can't seem to figure out this error . Error Property 'uniqueAddress' does not exist on type 'ObjectId'.

I do understand that mongoose.Types.ObjectID does not have my property uniqueaddress since I created that but then how am I suppose to use Populate and ref ?

Code is below

import mongoose, { Document, Model } from 'mongoose';

export interface TagToSync {
    name: string,
    createdBy: string,
}

interface UserDocument extends Document {
  uniqueAddress: string;
  submittedContent: Array<mongoose.Types.ObjectId>;
  createdAt: Date;
  updatedAt: Date;
  synced: boolean;
}

interface TagDocument extends Document {
  name: string;
  content: Array<mongoose.Types.ObjectId>; // comes from content schema not posting here
  createdBy: mongoose.Types.ObjectId; 
  synced: boolean;
}

const UserSchema = new mongoose.Schema<UserDocument>({
  uniqueAddress: {
    type: String,
    required: true,
    unique: true,
  },
  submittedContent: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Content',
  }],
  createdAt: {
    type: Date,
    default: Date.now,
  },
  updatedAt: {
    type: Date,
    default: Date.now,
  },
  synced: {
    type: Boolean,
    default: false,
  },
});
const User: Model<UserDocument> = mongoose.model('User', UserSchema);


const TagSchema = new mongoose.Schema<TagDocument>({
  name: {
    type: String,
    required: true,
    unique: true,
  },
  contents: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Content',
  }],
  createdBy: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true,
  },
  synced: {
    type: Boolean,
    default: false,
  },
});

const Tag: Model<TagDocument> = mongoose.model('Tag', TagSchema);


export const getTagsToSync = async () : Promise<TagToSync[]> => {
  return Tag.find({ synced: false })
    .populate({
      path: 'createdBy',
      model: 'User',
      select: 'uniqueAddress'
    })
    .then(tags => tags.map(tag => ({
      name: tag.name,
      createdBy: tag.createdBy.uniqueAddress
    })));
}

Solution

  • So I learned , I cannot directly cast it to UserDocument but first cast to Unknown then to UserDocument:

    return Tag.find({ synced: false })
            .populate({
            path: 'createdBy',
            model: 'User',
            select: 'uniqueAddress'
            })
            .then(tags => tags.map(tag => {
                const createdBy = (tag.createdBy as unknown) as UserDocument
                return {
                    name: tag.name,
                    createdBy: createdBy.uniqueAddress,
                }
            }))