Mongoose As The Data Access Layer
The role of
mongoose is to act as the data access layer - bridging JS code and the MongoDB storage layer.
Thinking of something like JDBC in the RDBMS world, the data access layer is expected to be fast and transparent - almost invisible.
mongoose, on the other hand, is actually designed to act as a complementary extension to MongoDB, making it more structured and organized - vs. just passing data back and fourth.
mongoose "intelligence" certainly makes it a significant additional external dependency for the implemented solution, so for those who prefer sticking with a thin data access layer - skip
mongoose and use MongoDB Node.JS Driver
In the latest versions,
mongoose has caught up with the
async/await JS coding paradigm, so that is the mode used in the demo project.
First thing when running 'mongoose' is establishing the DB connection. Here's surprise #1: due to its buffering feature,
mongoose may start executing pieces of code like queries or updates in the off-line mode - before the DB connection is in place. It is one thing to work off-line if an established connection flickers, but start processing data before the DB acknowledges and authenticates - sounds crazy. Well, apparently, this is a feature of the MongoDB Node.js Driver. Buffering can be disabled by setting
bufferMaxEntries to 0 and
bufferCommands to false in the connection properties. In the demo project, the default buffering is kept - as the app is coded to shut down if the initial
mongoose connection can't be established. The expectation is that the app won't get too far while the connectivity is pending to worry about this feature.
mongoose keeps the connection alive by default, so that it doesn't get timed out by the MongoDB server while the app is idle.
Keep in mind, like many other DBs, MongoDB does limit the number of active connections: check your Atlas tier specifications (you'll find the limits quite generous). By default,
mongoose creates a 5-connection pool to the DB for multi-threading. Parallel processing may potentially affect the results if you run frequent, very close to each other, partial Document updates and/or query Documents being updated - but rather hypothetically. As mentioned earlier - MongoDB is not your platform to implement transaction-dependant flows.
MongoDB Collections are accessed via
mongoose Models, which are built from Schemas. A Schema contains all field-level definitions and properties of a Document: types, defaults, and much more.
mongoose documentation, Documents are JS Objects that are instances of
mongoose Models - makes sense on the JS side. The necessity of the Schema layer, though, seems questionable: why not just put the definitions listed in the Schema directly into the Model? One clue may be that not every Schema is equal to a Model: embedded objects can be defined in a separate Schema and reused in multiple parent Schemas. Also, Model in
mongoose is described as a constructor compiled from Schema. Whatever.
MongoDB widely uses both Schema and Model concepts as well, but MongoDB Model is not a concrete element like it is in
mongoose - just a term used when describing design patterns.
Basically, trying to make a lot of sense cross-referencing terminology between MongoDB and
mongoose is not necessary to use the tool efficiently: you just write some code following a few simple patterns, like those plentiful in the demo project.
mongoose CRUD operations are executed on a
mongoose Model (which is MongoDB Collection, see the above). There are Schema-level operations, e.g., to define indexes. So, at a minimum, each Collection being accessed from the app via
mongoose must be present in the JS code as a
mongoose will help converting data types and defaulting values, including generation of Created At and Updated At timestamps. Although, beware, Updated At is left unchanged by some C-U-D operations.
mongoose will also validate data adherence to the
mongoose Schema, unless explicitly bypassed.
To invoke the async mode for each call vs. the old style
then mode, use the
exec() method to the command to the DB - you'll see examples throughout the demo project code.
In the Debug logging mode,
mongoose prints out details of operations and statements - very convenient for development and troubleshooting.
We'll look at the common
mongoose usage scenarios in the latter chapters, starting with review of the demo project Schemas and Models in the next lesson, read on!