MongoDB is a non-relational (or NoSQL) database. NoSQL databases like MongoDB have the concept of databases and collections while relational databases like MySQL have databases and tables. In a relational database you define a schema for each table in the database. This means that your tables will have a pre-defined set of columns and a value type that save your datasets in each row. A NoSQL database like MongoDB is schema-less. Instead of storing rows in a table you create “documents” that are stored in collections. Each document can be thought of as a kind of very efficient JSON file and a collection is, well, a collection of those documents. If you’r first learning Node.js you’ll probably be exposed to a lot of “MEAN Stack” tutorials that use Mongoose as the ORM. A point of confusion with Mongoose and part of the reason why I’ve personally stayed away from it for so long is because Mongoose seems to force you into defining a schema for your models and documents. But if MongoDB is schema-less doesn’t defining a schema sort of defeat the purpose of using it? The answer isn’t a simple yes or no and that’s what we’re going to explore today along with ways you can have the best of the schema-less and schema enforced world using Mongoose.
Why define a schema?
To newcomers to NoSQL the idea of defining a schema is weird and foreign to them at first. The whole idea is to be able to define random JSON documents and save them. But have you ever wondered how to pull these random documents out and figure out which properties were saved to document?
The truth is that for 90% of your web applications you’ll be using model classes and you’ll have a standard set of fields you’ll be expecting to be saved to your database. Mongoose models and their schemas allow you to perform validation on the fields you expect or are required. But if you stop there then you’ve just got the equivalent of a relational schema. So what’s the point? Why not just use a relational database?
Allow arbitrary fields in mongoose
There are certain kinds of data that defy classification. For example, some types of CRM software that require you to save data about a lead’s dependents (for tax purposes maybe) and other data that rarely needs to be accessed on its own but almost always needs to be displayed – and therefore stored – alongside the main model makes perfect sense within a non-relational database. One thing people overlook in the Mongoose docs is the second, optional options object you can pass to your Mongoose schema. This is an example of a Mongoose model schema that has a defined schema but also allows arbitrary fields to be stored to a document just like when using the native driver. You know, just in case we need to store an array of family member objects alongside a User model but the family member objects themselves are pretty useless on their own.
The Mongoose schema signature and an example of how to use it:
1 2 3 4 5 6 7 8 9 10 11
See that second object I passed to the Mongoose schema? I just told Mongoose that it should allow arbitrary fields. Boom. Now I can use Mongoose just like the native MongoDB Node driver. Of course this can be dangerous. You need to make sure you validate and sanitize these arbitrary fields.
Mongoose makes NoSQL models easy. But I recommend going with the native driver and doing the hard validation work manually. But hey, if you want to use Mongoose and want arbitrary fields that’s how you do it.
Alternatives to Mongoose
Mongoose may be the most popular NoSQL ORM but don’t forget that there are other options especially if you put an importance on the schema-less aspect of MongoDB. The official MongoDB driver uses the same exact API as the Mongo shell without having to define models or schemas. You simply connect to your database and then just use the Mongo library to save data any way you like.
As great as Mongoose is, the native MongoDB package for Node is my favorite. I know my schema and I want to easily be able to create custom documents and queries on the fly. To me, Mongoose is training wheels for the native Mongo driver.
So now that you know how to allow arbitrary fields to your Mongo documents go ahead and start enjoying this new freedom. Just be aware of the security vulnerabilities you’re exposing yourself to. I can’t tell you how to secure your schema-less documents because I don’t know your application but just know it’s possible and not difficult.