'cannot access mongoose schema static method - typescript

the issue i am having is the following - have a method called "findByToken()" which is defined in the model and also implemented as a static method in the userSchema.

In another part of my app i cannot access the method using: User.findByToken(token) - can you help me with this? can`t seem to find an answere anywhere.

import mongoose = require('mongoose');
import validator = require('validator');
import jwt = require('jsonwebtoken');

interface IUser {
  email: string,
  password: string,
  token: any[],
  generateAuthToken(): () => any
}

interface IUserModel extends IUser, mongoose.Document{
  findByToken: (token: any) => any;
  findByCredentials: (email: string, password: string) => any
}

let userSchema = new mongoose.Schema({
  email: {
      type: String,
      required: true,
      minlength: 1,
      trim: true,
      unique: true,
      validate: {
          validator: validator.isEmail,
          message: '{VALUE} is not a valid email'
      }
  },
  password: {
      type: String,
      required: true,
      minlength: 6
  },
  tokens: [{
      access: {
          type: String,
          required: true
      },
      token: {
          type: String,
          required: true
      }
  }]
});

userSchema.statics.findByToken = function(token: string) {
  let User = this; //entire model is binded with .this
  let decoded: any;

  try{
    decoded = jwt.verify(token, 'My Secret');
  } catch(e) {
      return Promise.reject('rejected');
  }

  return User.findOne({
    _id: decoded._id,
    'tokens.token': token,
    'tokens.access': 'auth'
  });
};


let User = mongoose.model<IUserModel>('User', userSchema);

export = User;

how i call the static methd:

import User = require('./../models/user');
import express = require("express");

/*
tsconfig.json:
   "strict": true     will enfore types for req, res, next - etc
*/


//creating our auth private middleware
let authenticate = (req: express.Request, res: express.Request, next: express.Request) => {
    let token = req.header('x-auth');

    //custom model method
    User.findByToken(token).then((user) => {
        // if(!user){
        //     return Promise.reject(); //sends you directly into catch
        // }

        // req.user = user;
        // req.token = token;
        // next();

    }).catch((e) => {
        res.status(401).send();
    });

}

User.find

export = authenticate;


Solution 1:[1]

Look at this example. You will see that you have to write some interfaces in order to get your statics, methods, virtuals and queries right

import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { ApiProperty } from "@nestjs/swagger";
import * as mongoose from 'mongoose';
import { Document } from 'mongoose';

@Schema()
export class User extends Document {
    @ApiProperty()
    @Prop()
    name: string;

    @ApiProperty()
    @Prop()
    birthday: Date;

}

interface UserMethods {
    sayHi()
}

interface UserQueries {
    byName(name: String)
}

interface UserVirtuals {
    virtualTest: string
}

export interface UserStatics {
    findByName(name:string)
}

export const UserSchema = SchemaFactory.createForClass(User) as mongoose.Schema<User, mongoose.Model<User, UserQueries, UserMethods, UserVirtuals>, UserMethods, UserQueries>;

UserSchema.methods.sayHi = function () {
    console.log(`Hi. My Name is ${this.name} and my birthday is ${this.birthday}`)
}

UserSchema.statics.findByName = function (name: string) {
    return this.find({name: new RegExp(name, 'i')})
}
UserSchema.query.byName = function (name: string) {
    return this.where({name: new RegExp(name, 'i')})
}
UserSchema.virtual("virtualTest").get(function () {
    return "this is a virtual test"
})
export const UserModel = mongoose.model(User.name, UserSchema) as mongoose.Model<any, UserQueries, UserMethods, UserVirtuals> & UserStatics

And yes the <any...> in this last line is important, because your IDEA will throw an error if you User instead and tries to use your methods or virtuals etc. But no worries! The IDEA will actualy autocomplete the methods anyway. Somehow it realizes, that the userObject that you create with

UserModel.create({...})

actualy has all the new memthods and virtuals. The & UserStatics adds static methods to your UserModel, so no error is highlighted by using them.

Solution 2:[2]

let User = mongoose.model<IUserModel>('User', userSchema);

should be:

let User = mongoose.model<IUser, IUserModel>('User', userSchema);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Diesel