TypeORM MongoDB Review
I recently started using TypeORM in a project with MongoDB and thought I’d share my thoughts on it.
TypeORM is typically used with SQL databases, but also has basic MongoDB support. Before I deciding to use TypeORM I tried doing some research online, but not too much came up. Others mentioned they were using it and it worked well enough for them, but didn’t go into too much detail. Hopefully this post covers those missing details for you and all the pain points you’ll face.
A quick summary of TypeORM from the homepage for those that haven’t used it before:
TypeORM is an ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript (ES5, ES6, ES7, ES8). Its goal is to always support the latest JavaScript features and provide additional features that help you to develop any kind of application that uses databases — from small applications with a few tables to large scale enterprise applications with multiple databases.
TypeORM supports both Active Record and Data Mapper patterns, unlike all other JavaScript ORMs currently in existence, which means you can write high quality, loosely coupled, scalable, maintainable applications the most productive way.
TypeORM is really popular for SQL, but the go to solution for Mongo is Mongoose (621,194 weekly npm downloads).
Mongoose does its job and is battle tested, but I have felt it to be a little cumbersome to use at times. For the project I’m working on it would have been more than fine. I wanted to see what else was out there.
One area where things could be nicer with Mongoose is when using it with TypeScript. If you want TS type support for your models, you need to define both the Mongo schema and the TypeScript types. I use GraphQL on almost all my projects too, which means having to define 3 different types for each collection.
One way to solve this problem with Mongoose is using a library called Typegoose which automatically generates TS types for you from your Mongoose models. I haven’t used this library so can’t comment on it, but it looks promising.
Another solution is to use TypeORM which will also auto generate the TS types for you.
There are unfortunately many basic features missing from TypeORM for MongoDB and this is the list of items I wish I had read before getting started with it:
Projection Support
MongoDB TypeORM does not support projections. There is an open pull request for it however:
Default Values
Default values don’t work. You’ll have to handle all values yourself when creating each object. Automatically adding createdAt
and updatedAt
fields is possible however with:
@CreateDateColumn({ type: 'timestamp' })createdAt: Date@UpdateDateColumn({ type: 'timestamp', nullable: true })updatedAt?: Date
Lack of Documentation
This page will help you out a bit:
But beyond that there’s not much out there. You can Google around for issues or read the source code to figure stuff out.
TypeORM was not built for MongoDB
This may be pointing out the obvious, but TypeORM’s focus is heavily on SQL. The first response in the PR I linked to above for example:
We can’t go with such changes. If we keep going with mongodb-specific changes entity-manager/repository is going to be a mess for rdbms and we’ll always be blocked on some absolute incompatible features.
I suggest to remove dependency of MongoEntityManager from EntityManager (e.g. remove extends) and completely re-implement MongoEntityManager with mongodb-specific features.
Nothing against the response and this approach may well make the most sense, but the simple point that the current state of TypeORM is not set up for MongoDB should be clear. It may be more MongoDB friendly in a year from now, but isn’t today.
Validation is broken
TS will give you an error if you try to save an object of the wrong shape to the database, but if you decide to add an object of type any
, the TS errors go away and you can add an item of any shape. So one piece of advice is to avoid any
here, but with a library like Mongoose, the data will be checked to be valid at runtime. This is also a problem if your project is in plain JavaScript.
You may need to convert to ObjectID format
Some methods support both String
and ObjectID
out the box (and will convert to the correct format if not already in it. For example, findOne
works fine whether you pass it a string id or as an ObjectID object.findOneAndUpdate
will not do this for you automatically however. A quick tip for getting around this problem is to use this helper function:
import { ObjectID } from 'mongodb'export const toObjectId = (value: string | ObjectID): ObjectID => { return typeof value === 'string' ? new ObjectID(value) : value}
It would be nice if this was supported out the box though.
Other Random Bugs
- If you
take
ororder
, you need to usewhere
in your query, otherwise it will ignore your selector. (You’ll notice it also uses SQL syntax rather thanlimit
orsort
that you may be used to from MongoDB). - And a few more, but best to see here for an up-to-date list: https://github.com/typeorm/typeorm/labels/driver%3A%20mongodb
That’s the list of problems I’ve encountered so far and what I wish I knew before starting to use the library. What I can say is that despite all of the above, the project is usable with Mongo. Just that better solutions exist out there. I also don’t mean to be disrespectful to the library maintainers and contributors that made MongoDB support possible.
Now that I’ve covered all the downsides of using the library, I’d like to cover some reasons you may still want to use it with MongoDB.
The first reason may be that you use TypeORM to connect to a SQL database, and using it to connect to MongoDB keeps things consistent.
Another reason is that it automatically generates TypeScript types for you as I mentioned above. But where this can get really nice is if you also use it with a library such as TypeGraphQL. This library automatically generates TS and GraphQL types for you (and I highly recommend taking a look at it).
What you can do when you use TypeORM and TypeGraphQL together is:
This defines my GraphQL schema and MongoDB model in the same file with TS types. I don’t have to edit 3 different pieces of code to add a new field. Doing something like this may also be possible when using Typegoose, but I haven’t tried it yet.
That is one super sweet feature and I came across it when watching one of Ben Awad’s videos. You can see an example using SQL here:
In summary, there are a lot of reasons not to use TypeORM with MongoDB today. As the TypeORM documentation mentions it’s still experimental and there’s a lot to still be worked out. If it’s a small enough project you can get away with using it, but I’d avoid it for a larger scale or public facing app.
About Me
I‘m a full-stack developer and founder of Skilled. Feel free to reach out at elie.tech or follow me on Twitter @elie222.
Newsletter
Stay up to date by subscribing to my newsletter.