Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose typescrypt this in pre middleware not exist

I learning mongoose typescrypt, and now trying to create schema and its middleware like this :

import { Schema, SchemaDefinition } from "mongoose";

export var userSchema: Schema = new Schema(<SchemaDefinition>{
    userId: String,
    fullname: String,
    nickname: String,
    createdAt: Date
});
userSchema.pre("save", function(next) {
    if (!this.createdAt) {
        this.createdAt = new Date();
    }
    next();
});

and i got error when tsc ini this.createdAt

src/schemas/user.ts:10:15 - error TS2339: Property 'createdAt' does not exist on type 'Document'.

I still dont know how to fix this, because i think no error.

please help me why is this error and how to solve this?

like image 567
yozawiratama Avatar asked Jun 20 '18 06:06

yozawiratama


2 Answers

Using function(next) in your second argument wont automatically bind this for you, but instead this will be Document.

Use the ES6 arrow function syntax as

userSchema.pre("save", (nex) => { ... });

and this will bind correctly.

If you stick with the old syntax you'll have to bind this yourself like

userSchema.pre("save", (function(next) {
    if (!this.createdAt) {
        this.createdAt = new Date();
    }
    next();
}).bind(this));
like image 70
Daniel B Avatar answered Nov 02 '22 04:11

Daniel B


As mentioned in comments, you wanted an example with typegoose which is kind of the TypeScript version of Mongoose.

In order to use decorator syntax in typescript, add this to your tsconfig.json's compiler options:

"emitDecoratorMetadata": true,
"experimentalDecorators": true

So, you can install typegoose like this:

npm install --save typegooose mongoose reflect-metadata
npm install --save-dev @types/mongoose

or

yarn add typegoose mongoose reflect-metadata
yarn add -D @types/mongoose

In your main endpoint file (server.js or index.js) include this at top:

import 'reflect-metadata';

You can connect to the database like this:

import * as mongoose from 'mongoose';
mongoose.connect('mongodb://localhost:27017/test');

Now let's define your user-model:

import {
    prop, Typegoose, pre
} from 'Typegoose';

// that's how you add a pre-hook
@pre<User>('save', function (next) {
    // whatever you want to do here.
    // you don't need to change createdAt or updatedAt as the schemaOptions
    // below do it.
    next()
})

// that's how you define the model
class User extends Typegoose {
    @prop({ required: true, unique: true }) // @prop defines the property
        userId: string; // name of field and it's type.
    @prop()
        fullName?: string;
    @prop()
        nickname?: string;
}

export const UserModel = new User().getModelForClass(User, {
    schemaOptions: {
        timestamps: true,
    }
});

Now, you can use the model like this:

import { UserModel } from './user'

(
    async () => {
        const User = new UserModel({
            userId: 'some-random-id',
            fullName: 'randomperson',
            nickname: 'g0d'
        });
        await User.save();

        // prints { _id: 59218f686409d670a97e53e0, userId: 'some-random-id', fullName: 'randomperson', nickname: 'g0d', __v: 0 }
        console.log(User);
    }
)();
like image 2
Daksh Miglani Avatar answered Nov 02 '22 04:11

Daksh Miglani