Chat App persists all data in MongoDB through three Mongoose models:Documentation Index
Fetch the complete documentation index at: https://mintlify.com/khushboodaryani/Chat-App/llms.txt
Use this file to discover all available pages before exploring further.
User, Message, and Conversation. Users are the root entity — every message and every conversation references User documents by their _id. Messages store both sender and receiver directly so they can be resolved independently. Conversations act as the join record that groups a pair of users with their shared message history, and Mongoose’s populate method is used to hydrate those message IDs into full documents at read time.
Connecting to MongoDB
The database connection is established inbackend/db/connectToMongoDB.js using Mongoose’s connect method. The connection string is read from the MONGO_URI environment variable.
connectToMongoDB is called inside the server.listen callback so the server only accepts traffic after the database connection is confirmed.
User Schema
Each document in theusers collection represents one registered account. Passwords are hashed with bcryptjs before the document is saved — the plain-text password never reaches MongoDB.
| Field | Type | Constraints | Notes |
|---|---|---|---|
fullName | String | Required | Display name shown in the UI |
username | String | Required, unique | Used for login; must be globally unique |
password | String | Required, minlength 6 | Stored as a bcryptjs hash |
gender | String | Required, enum ["male","female"] | Used to assign a default avatar URL |
profilePic | String | Default "" | URL of the user’s avatar image |
createdAt | Date | Auto (timestamps) | Displayed as “Member since …” in the UI |
updatedAt | Date | Auto (timestamps) | Managed by Mongoose |
The
password field is never returned in API responses. getUsersForSidebar appends .select("-password") to its query, and the protectRoute middleware also excludes it when attaching req.user. This is enforced at the database query layer, not in a serialisation helper.Message Schema
Each document in themessages collection represents a single chat message. Both the sender and the receiver are stored as direct references, which means a message can be resolved without traversing the Conversation collection.
| Field | Type | Constraints | Notes |
|---|---|---|---|
senderId | ObjectId → User | Required | The user who wrote the message |
receiverId | ObjectId → User | Required | The intended recipient |
message | String | Required | The plain-text message body |
createdAt | Date | Auto (timestamps) | Used to render the message timestamp |
updatedAt | Date | Auto (timestamps) | Managed by Mongoose |
Conversation Schema
Each document in theconversations collection represents the persistent channel between exactly two users. It holds a participants array of two User IDs and a messages array of Message IDs that grows as the conversation progresses.
| Field | Type | Notes |
|---|---|---|
participants | [ObjectId → User] | Always two entries — the two users in the conversation |
messages | [ObjectId → Message] | Ordered array of message IDs; defaults to [] on creation |
createdAt | Date | Auto (timestamps) |
updatedAt | Date | Auto (timestamps) |
Query Pattern: Finding a Shared Conversation
To fetch or create the conversation between two specific users, the message controller uses MongoDB’s$all operator to match conversations where both IDs appear in participants, regardless of their order in the array:
participants.
Populating Messages
When loading the message history for an open conversation,.populate("messages") replaces each ObjectId in the messages array with the full Message document:
Relationship Diagram
The three collections relate to each other as follows:- A Conversation contains exactly two User references in
participantsand an ordered array of Message references inmessages. - A Message stores its
senderIdandreceiverIdas direct User references, independent of the Conversation. This allows the Socket.io layer to emit a new message to the recipient immediately after saving, without re-querying the Conversation document. - A User has no embedded references to conversations or messages — all relationships are owned by the Conversation and Message documents, keeping the User schema lean.