Facebook Pixel

How to Design a Good Mongoose Schema

Schema design is a skill. Here is how to design Mongoose schemas that scale.

How to Design a Good Mongoose Schema

Schema design is the foundation of a MongoDB app. Bad schemas cause slow queries and data bugs. Here is how to design good Mongoose schemas.

1. Pick the Right Field Types

Use the right type for each field. String for text, Number for numbers, Date for dates, ObjectId for references, Boolean for flags, [String] for arrays of strings. Do not store numbers as strings; it breaks sorting and math.

2. Use Validation

email: { type: String, required: true, unique: true, lowercase: true, match: /^\S+@\S+\.\S+$/ }
password: { type: String, required: true, minlength: 8 }
age: { type: Number, min: 18, max: 120 }
gender: { type: String, enum: ['male', 'female', 'other'] }

Validation at the schema level prevents bad data at write time.

3. Use Defaults Where Helpful

createdAt: { type: Date, default: Date.now }
about: { type: String, default: 'Hey there!' }
photoUrl: { type: String, default: '' }

Saves clients from sending fields they do not care about.

4. Add Indexes Based on Queries

Index the fields you query and sort by:

  • Unique on email.
  • Compound on (fromUserId, toUserId) for connection requests.
  • On (connectionId, createdAt) for messages.

Do not index every field. Indexes speed up reads but slow down writes.

5. Use References for Large N

Use ref for one-to-many with large N (messages, connections, payments). Do not embed arrays that grow unboundedly.

senderId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }

6. Embed Small, Tightly Coupled Data

Embed when data is small and always loaded together (e.g., an address inside a user). Avoid embedding large or growing arrays.

7. Keep Documents Small

MongoDB has a 16MB document limit. Keep documents well under that. Large arrays and embedded subdocuments grow documents; use refs instead.

8. Use Timestamps

timestamps: true on the schema adds createdAt and updatedAt automatically. Use them; you will want them later for sorting and debugging.

const userSchema = new mongoose.Schema({ ... }, { timestamps: true });

9. Use Enums for Fixed Sets

For fields with a fixed set of values (status, role, gender), use enum. Prevents typos and invalid data.

10. Do Not Store Sensitive Data in Plain Text

Hash passwords with bcrypt before saving. Never store JWT secrets, API keys, or raw passwords. Mark sensitive fields with select: false so they are not returned by default.

passwordHash: { type: String, required: true, select: false }

The Takeaway

Design good Mongoose schemas with the right types, validation, defaults, indexes based on queries, refs for large N, embed for small data, small documents, timestamps, enums, and hashing for sensitive fields. Good schemas prevent slow queries and data bugs.

Pick the right field types, add validation (required, min, max, enum, match), use defaults, index the fields you query, use refs for large N, embed small data, keep documents small, use timestamps, use enums for fixed sets, and hash sensitive fields.

Use ref for one-to-many with large N (messages, connections). Use embed for small, tightly coupled data that always loads together (an address inside a user). Embedding large or growing arrays bloats documents; use refs instead.

Index the fields you query and sort by. Unique on email. Compound on (fromUserId, toUserId) for connection requests. On (connectionId, createdAt) for messages. Do not index every field; indexes speed up reads but slow down writes.

Pass { timestamps: true } as the second argument to new mongoose.Schema(). Mongoose will set and update both fields automatically. Use them; you will want them later for sorting and debugging.

Mark them with select: false. Example: passwordHash: { type: String, required: true, select: false }. They are excluded from find queries by default; you can still select them explicitly with .select('+passwordHash') when needed (e.g., for login).

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.