RDBMSs were a big step forward when compared to their non-relational predecessors. The network and hierarchical databases that predated the RDBMS were cumbersome and inflexible, and most developers welcomed the SQL language and the relational model.
However, the emergence of oriented programming in the 1990s created a conflict between the relational model and best practice programming. The eelational model required that data be “normalized”—which usually meant splitting a business objects across multiple tables. However, in the object-oriented programming paradigm, all attributes of an entity are encapsulated within an object class. As a result, persisting programming objects to an RDBMS involved a very tedious task of decomposing an object and writing it out to multiple rows within multiple tables. A similar tedious task of reconstructing an object was required when retrieving an object from the RDBMS.
This impedance mismatch led to the development of object relational mapping software (ORM). An ORM manages the mapping of a program object to its representation within an RDBMS. A programmer needs only “save” the object and the ORM layer will create the necessary SQL statements necessary to insert or update a representation of the object within the RDBMS. ORM layers such as Hibernate (for Java) became immensely popular and still represent best practice programming in many programming languages.
Despite the prevalence of ORM layers, the programming community continued to be dissatisfied with the disconnect between the world of Objects within the application code and the world of tables in the RDBMS. Several attempts to create object-oriented database management systems—OODBMS—occurred, but none managed to achieve widespread adoption.
Eventually, document-oriented database systems such as MongoDB and CouchBase came to the rescue. In MongoDB, a program object can be persisted to a single document, eliminating the friction between the database and the application code.
Applications written in NodeJS are particularly synergistic with MongoDB since JavaScript objects (JSON) are native to MongoDB and to Node. So, it might seem strange at first that an ORM-like layer—Mongoose—has emerged. Why would we want a mapping layer between JSON objects and a JSON database?
Strictly speaking, Mongoose is an ODM (Object Document Mapping) layer, not an ORM. However, most of the principles of ORM are implemented within the Mongoose ODM. In particular, Mongoose relieves you from the necessity of learning the idiosyncrasies of the MongoDB API. You don’t have to issue update or insert statements; instead you modify an object in NodeJS code and Mongoose handles the MongoDB interactions.
However, Mongoose has a broader ambition than most ORMs. While an ORM maps Objects to pre-existing relational database schemas, Mongoose implements schemas within the otherwise schemaless MongoDB database. When using Mongoose, the structure of all the documents in the database are defined by schemas declared within the Mongoose API. These schemas control the allowable attributes of an object, set defaults, provide validation rules and so on.
Mongoose also allows methods to be defined within schemas that can be used to encapsulate complex query or update behavior within the resulting object. The resulting Mongoose objects, therefore, have a more sophisticated functionality than simple JSON objects.
Advocates of Mongoose argue that it improves developer efficiency, results in cleaner and more readable code, and reduces the chance of inconsistent data structures within the database. A lot of developers appear to agree—according to Github over 870,000 projects have incorporated Mongoose!