In this lesson, you will learn how to bridge the gap between specialized database-native formats and usable JavaScript objects within your ORM.
Most relational databases offer "rich" data types that don't always map perfectly to standard JavaScript primitives like string or number. Common examples include UUID strings, JSONB blobs in PostgreSQL, or custom geometric types. If you try to save an object directly into a JSONB column, the database might store it as a stringified mess, and if you read it back, you'll be stuck parsing it manually every time.
To solve this, modern ORMs allow you to define a custom mapping layer. This tells the ORM how to transform data during two specific moments:
- Serialization (Outbound): When saving a JavaScript object to the database.
- Deserialization (Inbound): When retrieving data from the database back into your application.
Practical Example: JSONB Storage
Imagine you have a User model with a preferences field stored as JSONB. You want your code to interact with it as a simple JavaScript object, but the database expects a stringified format.
// Defining a custom mapper for JSONB
const PreferencesType = {
// Convert JS Object to DB String
toDatabase(value) {
return JSON.stringify(value);
},
// Convert DB String back to JS Object
fromDatabase(value) {
return typeof value === 'string' ? JSON.parse(value) : value;
}
};
// Applying it to your model definition
const User = sequelize.define('User', {
preferences: {
type: DataTypes.TEXT,
get() {
return PreferencesType.fromDatabase(this.getDataValue('preferences'));
},
set(value) {
this.setDataValue('preferences', PreferencesType.toDatabase(value));
}
}
});
By leveraging get() and set() methods (which you previously learned in lesson 4), you act as a translator. The rest of your application code remains clean—it simply interacts with user.preferences.theme without needing to know that the underlying database is doing the heavy lifting of stringification. This pattern is equally powerful for UUID generation or normalizing complex coordinate arrays into GeoJSON structures.
Key Takeaway: Mapping custom database types allows you to keep your application logic clean by automatically transforming complex database data into native JavaScript objects upon retrieval and back again before saving.