Database Schema
Relevant source files
The following files were used as context for generating this wiki page:
This document provides a detailed overview of the MongoDB database schema for the AirZen air quality monitoring system. The schema is defined using Mongoose, an Object Data Modeling (ODM) library for Node.js, which provides a straightforward, schema-based solution to model application data. The database is structured to store information about users, IoT devices, and their associated sensors.
The core collections in the database are User (or TaiKhoan), ThietBi (Device), and CamBien (Sensor). These collections work together to manage user accounts, track physical monitoring devices, and store data from individual sensors.
Entity Relationship Diagram
The diagram below illustrates the relationships between the main collections in the database. A ThietBi (Device) can have multiple CamBien (Sensors) associated with it.
Models
User / TaiKhoan Model
The User model, defined in backend/src/models/User.js, stores user account information, including credentials, roles, and status. There is a similar, less detailed schema named TaiKhoan in backend/src/models/TaiKhoan.js which is imported by some controllers. The User.js schema is more comprehensive and includes advanced features like password hashing and instance methods.
Sources: backend/src/models/User.js, backend/src/controllers/userController.js:5
Schema Definition
| Field | Type | Constraints | Description |
|---|---|---|---|
name | String | required, trim, max 50 chars | User's full name. |
email | String | required, unique, lowercase, regex match | User's email address, used for login. |
password | String | required, min 6 chars, select: false | Hashed user password. Not returned in queries by default. |
avatar | String | default: "" | URL to the user's avatar image. |
role | String | enum: ["user", "admin"], default: "user" | User role, determining permissions. |
isActive | Boolean | default: true | Flag to enable or disable the account (soft delete). |
createdAt | Date | default: Date.now | Timestamp of account creation. |
lastLogin | Date | - | Timestamp of the user's last login. |
timestamps | Boolean | true | Automatically adds createdAt and updatedAt fields. |
Sources: backend/src/models/User.js:10-53
Middleware and Methods
- Password Hashing: A
pre('save')middleware automatically hashes the user's password usingbcryptjswith a salt round of 12 before saving it to the database. This only runs if the password field has been modified.
Sources: backend/src/models/User.js:70-84 comparePassword(candidatePassword): An instance method to compare a plain-text password with the stored hash.
Sources: backend/src/models/User.js:91-93updateLastLogin(): An instance method to update thelastLoginfield to the current time.
Sources: backend/src/models/User.js:96-99findActive(): A static method to find all users whereisActiveistrue.
Sources: backend/src/models/User.js:105-107findByEmail(email): A static method to find a user by email, explicitly including thepasswordfield for authentication purposes.
Sources: backend/src/models/User.js:110-112
Indexes
To optimize query performance, the following indexes are defined on the User collection:
- A unique index on
email. - An index on
createdAtfor sorting by creation date. - An index on
isActivefor filtering active users.
Sources: backend/src/models/User.js:118-120
ThietBi Model (Device)
The ThietBi model represents a physical IoT device. It is defined in the ThietBi collection.
Sources: backend/src/models/ThietBi.js
Schema Definition
| Field | Type | Constraints | Description |
|---|---|---|---|
_id | String | - | Custom unique identifier for the device. |
TenThietBi | String | required, trim | The name of the device. |
ID_NhaSanXuat | String | default: "" | ID of the manufacturer. |
NgayNhap | Date | default: Date.now | The date the device was added to the system. |
timestamps | Boolean | true | Automatically adds createdAt and updatedAt fields. |
Sources: backend/src/models/ThietBi.js:5-20
CamBien Model (Sensor)
The CamBien model represents a sensor that is part of a ThietBi. It is stored in the CamBien collection and is linked to a device via the ID_ThietBi field.
Sources: backend/src/models/CamBien.js
Schema Definition
| Field | Type | Constraints | Description |
|---|---|---|---|
id | String | - | Custom identifier for the sensor (e.g., CB001). |
ID_ThietBi | String | required, ref: "ThietBi" | The ID of the parent device this sensor belongs to. |
LoaiCamBien | String | required | The type of the sensor (e.g., Temperature, CO2). |
ThongSoKyThuat | String | default: "" | Technical specifications of the sensor. |
TrangThai | String | enum: ["online", "offline"], default: "offline" | The current status of the sensor. |
NgayUpdate | Date | default: Date.now | The last time the sensor's data was updated. |
ID_LoaiCamBien | String | default: "" | An ID for the sensor type. |
timestamps | Boolean | true | Automatically adds createdAt and updatedAt fields. |
Sources: backend/src/models/CamBien.js:5-32
Indexes
- An index on
ID_ThietBito speed up lookups for sensors belonging to a specific device. - An index on
TrangThaito efficiently filter sensors by their status.
Sources: backend/src/models/CamBien.js:34-35
Data Relationships and Usage
The primary relationship is between ThietBi and CamBien, where one device can have many sensors. This is implemented by storing the device's _id in the ID_ThietBi field of each associated sensor document.
The GET /api/thietbi endpoint demonstrates how these two collections are joined using a MongoDB aggregation pipeline. The $lookup stage is used to fetch all camBien documents that match the _id of a ThietBi.
Sources: backend/src/routes/thietBi.js:6-59
The following diagram shows the aggregation flow for retrieving devices along with their sensors.
This diagram illustrates the aggregation process defined in backend/src/routes/thietBi.js.
Sources: backend/src/routes/thietBi.js:11-50