22 Building Sub-Schemas Based on Modules
22 Building Sub-Schemas Based on Modules: A Practical Guide to Modular Data Architecture
In modern application development, especially when we talk about large-scale systems or microservices, managing data schemas often becomes a challenge in its own right. One widely adopted approach is schema modularization — where each application feature module has its own sub-schema. In this article, we’ll take an in-depth look at building sub-schemas based on modules in a backend project, complete with code examples, case simulations, and a flow diagram showing how an integrated schema is composed.
Why Do We Need a Sub-Schema per Module?
Let’s start with a fundamental question: Why do we need to build sub-schemas based on modules?
Here are a few reasons:
- Cleaner code organization: A specific feature’s data schema lives only inside its own module folder.
- Easier scaling and maintainability: When adding or changing a feature, you only need to touch the related parts.
- Avoiding the “God Entity”: A single massive schema file makes the data model hard to maintain and prone to conflicts when engineers collaborate.
Case Study: A Simple CRUD Project
Let’s assume we’re building a simple RESTful application with two main modules: Users and Posts. Each has its own schema and logic. We’ll use MongoDB and Mongoose on Node.js to illustrate the implementation.
A modular project folder structure:
1src/
2│
3├── modules/
4│ ├── user/
5│ │ ├── user.model.js
6│ │ └── user.controller.js
7│ └── post/
8│ ├── post.model.js
9│ └── post.controller.js
10│
11├── app.js
12└── database.jsBuilding Sub-Schemas: An Example Implementation
1. User Schema
1// src/modules/user/user.model.js
2const mongoose = require('mongoose');
3
4const userSchema = new mongoose.Schema({
5 name: { type: String, required: true },
6 email: { type: String, unique: true },
7 password: { type: String, required: true },
8 createdAt: { type: Date, default: Date.now }
9});
10
11module.exports = mongoose.model('User', userSchema);2. Post Schema with a Sub-Schema (Embedded)
It gets more interesting if, in the Post module, we embed a dedicated Comment sub-schema:
1// src/modules/post/post.model.js
2const mongoose = require('mongoose');
3
4const commentSchema = new mongoose.Schema({
5 user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
6 message: { type: String, required: true },
7 postedAt: { type: Date, default: Date.now }
8}, { _id: false }); // Sub-schema: comments don't need a separate _id
9
10const postSchema = new mongoose.Schema({
11 title: String,
12 content: String,
13 author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
14 comments: [commentSchema] // Array of sub-schemas
15});
16
17module.exports = mongoose.model('Post', postSchema);The benefit:
The Comment sub-schema is DIFFERENT from the main User and Post schemas, so it can evolve independently according to the needs of Post.
Simulating Relationships and Modularization
As shown below, each module is responsible for its own sub-schema. To illustrate relationships and modularity, here is a flow diagram of how data is handled when adding a new post along with its comments:
flowchart TD
A[Client Request: Buat Post] --> B[Modul Post Menerima Request]
B --> C[Akses User (author) dari Modul User]
C --> D[Lolos? Continue, Gagal? Reject]
D --> E[Modul Post Membuat Data Post (dengan Comments sbg Sub-Schema)]
E --> F[Simpan ke Database]
F --> G[Response ke Client]
The flow above is clearly modular: the Post module manages Post + Comment, while the User module is merely a reference. The Comment sub-schema belongs exclusively to Post.
Table Comparison: Modularization vs. Global Schema
| Approach | Advantages | Disadvantages |
|---|---|---|
| Global Schema | Schema simplification (one place for the model) | Hard to maintain, error-prone |
| Modular Sub-Schema | Easy to develop per module, scalable | Requires integration & dependency strategy |
Tips & Best Practices for Modular Sub-Schemas
Separate the Schema Folder per Module
So the source code is easy to maintain and scalable.Don’t Duplicate Schemas Across Modules
If there’s a small schema used by many modules (e.g.,Address), put it in shared schemas.Use References for Large Entities
For large or rapidly changing data (e.g., User), MongoDB recommends usingrefrather than an embedded sub-schema.Write Unit Tests for Every Schema
Modularization makes it easier to write isolated unit tests for your models.
Integrating All Sub-Schemas: The Application Entry Point
When the app runs, the main app typically registers all schemas at the entry point, but the schema code and logic remain delegated to each module. For example:
1// app.js
2const express = require('express');
3const mongoose = require('mongoose');
4
5// Connect to MongoDB (per the database.js file)
6mongoose.connect('mongodb://localhost:27017/myapp');
7
8const app = express();
9app.use(express.json());
10
11// Import routers from each module
12const userRoutes = require('./modules/user/user.controller');
13const postRoutes = require('./modules/post/post.controller');
14
15app.use('/users', userRoutes);
16app.use('/posts', postRoutes);
17
18app.listen(3000, () => console.log('Server running at http://localhost:3000'));Simulating an API Request
Create a new Post:
1POST /posts
2{
3 "title": "Membuat Sub-Schema Modular",
4 "content": "Sub-schema itu solusi arsitektural yang powerful.",
5 "author": "665e752f92a014c5efa4fbc9",
6 "comments": [
7 {"user": "665e752f92a014c5efa4fbc9", "message": "Nice post, thanks!"}
8 ]
9}The server’s response will contain the comments as sub-documents inside comments.
Conclusion: When Should You Modularize Your Schema?
Schema modules are especially useful for:
- Fast-growing applications with many new features
- Development teams larger than 3 people
- Backends preparing for a microservices/service-oriented monolith architecture
With a sub-schema per module, your backend project’s architecture becomes robust and scalable.
“Modularizing schemas is an investment in maintainability. It might seem verbose at first, but it pays off quickly as your team and app grows.”
We hope the explanations and simulations in this article, “Building Sub-Schemas Based on Modules,” help give you solid insight into backend architecture that’s ready to scale! Don’t hesitate to try schema modularization in your next project. 🚀
References