Database Models
Overview
The Notes App uses MongoDB as its database with Mongoose as the Object Document Mapper (ODM). Mongoose provides a schema-based solution to model application data, adding structure and validation to the flexible MongoDB documents.
What is Mongoose?
Mongoose is a JavaScript library that acts as a bridge between Node.js and MongoDB. It provides:
- Schema definitions - Structure for documents with data types and validation
- Model creation - JavaScript classes that represent collections in MongoDB
- Query building - Methods to interact with the database
- Middleware - Functions that run before or after certain operations
Database Connection
The application connects to MongoDB using the connection string from config.json
:
const mongoose = require("mongoose");
const config = require("./config.json");
const db_url = config.connectionString;
mongoose.connect(db_url);
This establishes a connection to the MongoDB database when the server starts.
User Model
File: backend/models/user.model.js
The User model represents user accounts in the system.
const userSchema = new Schema({
fullName: {type: String},
email: {type: String},
password: {type: String},
createOn: {type: Date, default: new Date().getTime()},
})
Schema Fields Explained
- fullName: Stores the user's display name as a string
- email: Stores the user's email address for login identification
- password: Stores the user's password (stored as plain text - security concern)
- createOn: Timestamp of when the account was created, defaults to current time
Key Characteristics
- No validation: The schema doesn't enforce required fields or email format validation
- Plain text passwords: Passwords are stored without encryption (not recommended for production)
- Simple structure: Minimal fields for basic user management
Usage in Application
The User model is used for:
- Account creation (
/create-account
endpoint) - User authentication (
/login
endpoint) - User information retrieval (
/get-user
endpoint)
Note Model
File: backend/models/note.model.js
The Note model represents individual notes created by users.
const noteSchema = new Schema({
title: {type: String, required: true},
content: {type: String, required: true},
tags: {type: [String], default: []},
isPinned: {type: Boolean, default: false},
title: {type: String, required: true}, // Duplicate field
userId: {type: String, required : true},
createOn: {type: Date, default: new Date().getTime()},
})
Schema Fields Explained
- title: The note's title (required field, appears twice due to error)
- content: The main text content of the note (required)
- tags: Array of string tags for categorization (defaults to empty array)
- isPinned: Boolean flag to mark important notes (defaults to false)
- userId: Links the note to its owner (required for data isolation)
- createOn: Timestamp of note creation
Key Characteristics
- Required fields: Title, content, and userId must be provided
- Default values: Tags default to empty array, isPinned defaults to false
- User association: Each note belongs to a specific user via userId
- Schema error: Title field is defined twice (line 4 and 8)
Usage in Application
The Note model supports all note operations:
- Creating notes (
/add-note
endpoint) - Editing notes (
/edit-note/:noteId
endpoint) - Deleting notes (
/delete-note/:noteId
endpoint) - Pinning/unpinning (
/update-note-pinned/:noteId
endpoint) - Retrieving all notes (
/get-all-notes
endpoint) - Searching notes (
/search-notes
endpoint)
Data Relationships
User to Notes Relationship
The application implements a one-to-many relationship:
- One User can have many Notes
- Each Note belongs to exactly one User
This is achieved through the userId
field in the Note model, which stores the User's MongoDB _id
.
// When creating a note
const note = new Note({
title,
content,
tags: tags || [],
userId: user._id, // Links note to user
});
Data Isolation
User data is isolated by always filtering notes by userId
:
// Get user's notes only
const notes = await Note.find({ userId: user._id });
// Edit only user's own notes
const note = await Note.findOne({ _id: noteId, userId: user._id });
Database Operations
Common Query Patterns
Find by user: Note.find({ userId: user._id })
Sort by pinned status: .sort({ isPinned: -1 })
(pinned notes first)
Search with regex: { title: { $regex: new RegExp(query, "i") } }
(case-insensitive)
Find one specific note: Note.findOne({ _id: noteId, userId: user._id })
MongoDB Features Used
- Regular expressions for search functionality
- Sorting to prioritize pinned notes
- Array fields for tags storage
- Boolean fields for pinned status
- Date fields with default values
Security Considerations
Current Issues
- Plain text passwords: User passwords are stored without hashing
- No input validation: Schema lacks validation rules for email format
- No field constraints: Missing length limits or format requirements
Data Access Control
The application properly implements user data isolation by always including userId
in database queries, ensuring users can only access their own notes.