Complete Guide for using Typescript in Mongoose with lean() function

Jason Ching
3 min readJan 2, 2021

Typescript has become the new standard in Javascript, but doing typescript right in Mongoose is not an easy task.

In this article, I am going to show you an example of doing it right with consideration of:

  • Writing the minimal code necessary
  • Using the lean() function
  • References between model

TLDR; The Code;

As a developer, you should feel more comfortable of reading code than reading my words. So, I am showing you all the code here directly.

This example contains 2 models: UserModel and PostModel. The PostModel has an reference back to the UserModel. A very typical 1 to many relationship data modeling. Each model has 2 interfaces and 1 type.

You don’t need @types/mongoose

Here is the catch, you don’t have to install @types/mongoose. The latest version of mongoose has already include typescript support, but the official doc is just not telling you.

yarn add mongoose

It will break if you install the @types/mongoose package.

The Model vs the Doc Instance

To understand what’s going on here, you need to have a clear understanding of the difference between model and doc.

The model, UserModel and PostModel in our example, represents a collection. You can do constructing, querying, deleting, and updating.

The document instance, UserDoc and PostDoc in our example, represent a single document. It contains the document properties. The doc instance also track changes. You can update the document and save it back to database.

Understand more about this in the Mongoose official doc here.

Rule #1: Use Lean Whenever You Can

Since the document instance is tracking changes, there are few things you need to be careful:

  • It comes with a price. There is overhead.
  • You don’t need it most of the time.
  • You need to be very clear where you are dealing with the database operation. It’s always a good idea to isolate database operation in a specific area of your code. Once you are done with it, you get out of it. Bringing the document instance to other modules/layers of your code may result in unexpected side effect. It’s messy and hard to debug.

With all these concern, you shouldn’t be using the doc instance extensively. All you need to have most of the time is a POJO (Plain Old Javascript Object) that simply holding the data of your document. That’s what the lean() function give you. Read more about this here.

Rule #2: Don’t use virtual and instance method

Mongoose provides a convivence way to define virtual and method in the doc instance. This enrich the functionality of your document. But it would not be cost effective to stop us using the lean object because of this.

You can just create helper functions for these which give you the same functionality but just write few more characters in your code.

We have created a userModelHelper in above user.model.ts file for this purpose.

Type Explain: DocPoJo

This is your POJO (Plain Old Javascript Object) interface that defines your schema here. We are not going to use this directly most of the time, but other interfaces and types will do inheritance from this.

UserPoJo is the minimum you need when you create a document

Type Explain: Doc

This represents your document instance. It is inherited from both DocPoJo and mongoose.Document.

The UserDoc instance is returned from the model. It is tracking changes and you can do database operation like update() here.

Type Explain: User Model

The this the main model interface you are going to work with. All the database operation you need should be done here, such as create() and find().

If you have static methods, you can define them here.

Type Explain: DocLean

The latest mongoose typescript suppport has a nice type alias LeanDocument<T>. This is a really a complicated typescript stuff if you wanna dive into that. You can get more idea about this here.

For simplicity and consistency, we are creating another type alias on top of it.

The DocLean type will only have the document properties but no other functions. It’s very similar to the DocPoJo except that the you have the _id property here, but the PoJo type don’t.

This is how you get the lean instance back. I am explicitly defining the UserDocLean type here to show you the type. You don’t really need to do that in your code.

The lean instance has all properties inherited from the PoJo type and also the _id property.

The Reference

You can declare your reference in the PoJo interface.

In this example, our post document is referencing the user document.

Notice that we are using the lean type for user here, so that it gives us back a nice POJO.

You can just use it like this. Nice and easy.

Conclusion

Getting all this done right is not an easy task. MongoDB is a scheme-less database. Now we are apply schema restriction to it. That’s where all the hassle comes in.

To Do

I can’t get query chaining working yet…

--

--