francescov1 / mongoose-tsgen

A plug-n-play Typescript generator for Mongoose.
105 stars 24 forks source link

Reference / Population issue #26

Closed www-chique closed 3 years ago

www-chique commented 3 years ago

Hey, in response to #19

Many thanks for working on the Query and the 7.0.0 update.

However, I noticed it does interfere with "Ref" / population. If there is a column with "ref", pointing to another Model, then using the _id field shows an error, so does any other method.

A quick example:

const SessionSchema = new Schema(
    {
        user: {
            type: Schema.Types.ObjectId,
            ref: "User",
            required: true,
        },
        owner: {
            type: Schema.Types.ObjectId,
            ref: "User",
            required: true,
        },
    },
    {
        timestamps: true,
    }
);

Afterwards, using populate on the "user" field, gave me 2 kinds of errors

  1. Trying to use session.user._id (session is a document of Session model, with populated 'user' field) shows Property '_id' does not exist on type 'ObjectId | UserDocument | (ObjectId & User) | (Document<ObjectId> & UserMethods & { externalId: {}; totp: {}; passwordReset: DocumentArray<...>; referrers: DocumentArray<...>; } & User & ObjectId)'. Property '_id' does not exist on type 'ObjectId'.

  2. Trying to use a method of User model on this populated field, like session.user.hasRole('foo'), shows Property 'hasRole' does not exist on type 'ObjectId | UserDocument | (ObjectId & User) | (Document<ObjectId> & UserMethods & { externalId: {}; totp: {}; passwordReset: DocumentArray<...>; referrers: DocumentArray<...>; } & User & ObjectId)'. Property 'hasRole' does not exist on type 'ObjectId'

Note: The problem is not there in version 6.0.10

francescov1 commented 3 years ago

This is due to stronger typing with Mongoose now. Typescript does not know if session.user is an ObjectId or a populated document. Here's how you can handle populated documents:

// fetch `session` with user populated
const session = await Session.findById(sessionId).populate("user").exec()

// typecast user as UserDocument
const user = session.user as UserDocument;

// UserDocument properties are accessible
console.log(typeof user._id); // ObjectId

or shorter:

...

console.log(typeof (session.user as UserDocument)._id); // ObjectId

In the future I'm looking to improve this by using populate function calls to determine whether a ref is populated or not. This will remove the need to explicitely state the ref type as it will be inferred.

www-chique commented 3 years ago

Thank you so much. That solved the problem.

francescov1 commented 3 years ago

Will make a note in the docs!