ORMs and ODMs
ORMs (Object-Relational Mapping) and ODMs (Object-Document Mapping) are abstraction layers that sit between an object-oriented programming language and a database. They allow devs to interact with data using the native paradigms of their language (like classes, objects, or types) instead of writing raw database queries.
Essentially, they translate database records or documents into live code objects, and vice versa, automating the tedious parts of data persistence.
| Feature | ORMs (Object-Relational Mapping) | ODMs (Object-Document Mapping) |
|---|---|---|
| Target Database | Relational (SQL) (e.g., PostgreSQL, MySQL, SQLite) | Document-Oriented (NoSQL) (e.g., MongoDB, CouchDB) |
| Data Structure | Tables, rows, and rigid schemas. | Collections, JSON-like documents, and flexible schemas. |
| Relationships | Managed via foreign keys and junction tables (JOINs). |
Managed via embedded documents or references ($lookup). |
| Common Examples | Prisma, Sequelize, SQLAlchemy, Hibernate, TypeORM | Mongoose, Mongoid, Doctrine ODM. |
development approaches
Code First Approach
create classes and entities first and database schema gets created from that
Database First Approach
have a running database already with the schema you want, and run some tooling to reverse engineer that and create classes based on the schema
Virtual Items
In Mongoose (and other ORMs/ODMs),Ā virtual fieldsĀ (often referred to simply as "virtuals") are document properties that you can get and set butĀ are not persisted to the database. They exist only in the application code.
two types:
-
Calculated Virtuals (Getters/Setters)
These are properties computed on the fly based on other fields stored in the database.
Example:deviceAgeyou should calculate on the fly based onmanufacturedDate. If you storeddeviceAgeon the DB it would constantly become outdated. -
Virtual Populate (Relationship Virtuals)
This is a Mongoose-specific feature used to represent relationships (like "virtual items" belonging to a wishlist) without storing arrays of ObjectIds in the database.
example: if a Wishlist has 10k WishlistItems storing an array of 10k ObjectIds inside the Wishlist document can cause performance bottlenecks and risks hitting MongoDB's 16MB document size limit. So only the child stores theĀwishlitId, and the parent queries it virtually.
When you query a Wishlist, theĀitemsĀ property is empty by default. However, you can callĀ.populate("items")Ā on your query, and Mongoose will automatically query theĀwishlistitemsĀ collection behind the scenes and populate the array.
By default, MongoDB driver ignores virtuals when sending data back as JSON. To make them visible to the frontend, you must explicitly enable them in the schema options, as seen at the bottom of the schemas:
{
toJSON: { virtuals: true },
toObject: { virtuals: true }
}