1

I have a mongoose schema in typescript and I am already using an interface for properties of the document itself. I want to create a class so when I find a document I can immediately call methods. I also want the document to contain members that are instances of other classes and call the methods those members. Is this possible? Here is what I have so far:

models/user.ts:

import mongoose from '../lib/mongoose';
const Schema = mongoose.Schema;

interface IUser extends mongoose.Document {
  username: string;
  email: string;
  hash: string;
};

var userSchema = new Schema({
    username: String,
    email: String,
    hash: String
});

export default mongoose.model<IUser>('User', userSchema);

I don't actually need to do this for my user model but it is the shortest so I thought it would be a good example. Let's say I wanted a method to check if the user's email contains their username.

Here is a simple user class:

class User {
  constructor(public username: string, public email: string, public hash: string) {

  }

  emailUsernameCheck(): boolean {
    return this.email.includes(this.username);
  }
}

I want to be able to make a call like this:

import User from '../models/user';
User.findOne({username: 'foo'}).emailUsernameCheck();

Let's also say I wanted to give each user a square with a height and width, and the square class has an area method.

Here is a sample square class:

class square {
  constructor(public height: number, public width: number) {

  }

  area(): number {
    return this.height * this.width;
  }
}

I also want to be able to make a call like this:

import User from '../models/user';
User.findOne({username: 'foo'}).square.area();

I know I can make the classes separately, give them constructors that take objects, and construct the classes that way. I will do this if it is the only way but it means importing the class separately and adds an extra step to every database lookup. It also opens up room for error since the classes are maintained separately from the schema. I would love to handle this all in my model. Is there something I can add to models/user.ts so I can do things like the examples above?

user5505266
  • 593
  • 5
  • 20

1 Answers1

0

I think is not possible to use a separate Class in mongoose.

Btw you can copy methods from an external object and prototype to Schema.* and Schema.methods.*, but the final object won't share the same prototype as the source class (instanceof).

Community
  • 1
  • 1
Dario
  • 3,905
  • 2
  • 13
  • 27
  • I found a mongoose plugin that does what I want called [mongoose-class-wrapper](https://www.npmjs.com/package/mongoose-class-wrapper). – user5505266 Nov 28 '16 at 19:08
  • The problem is that it doesn't do the second thing I wanted, still looking into that, though as you said it looks impossible. – user5505266 Nov 28 '16 at 20:41
  • Yes, sadly I think is not possible. Also the plugin you posted, do exactly what I suggested (copy methods) so you won't use `instanceof` or inheritance (`extends`), because is just a composition https://github.com/aksyonov/mongoose-class-wrapper/blob/master/src/index.js#L14 – Dario Nov 29 '16 at 09:03
  • Thanks for the help. I think I will just make a class of static methods that take objects that implement the interface. – user5505266 Nov 29 '16 at 17:12