How do you model data and enforce schemas with Mongoose/MongoDB?

3 minintermediatenodejsmongodbmongooseschemanosql

Quick Answer

MongoDB stores schemaless BSON documents; Mongoose adds an application-level schema layer with types, validation, defaults, and middleware. You model data around access patterns — embedding related data for read-together documents, referencing for large or independently-queried data.

Detailed Answer

Answer: MongoDB itself is schemaless — documents in a collection can differ. Mongoose is an ODM that imposes structure, validation, and convenience at the application level.

Defining a schema and model:

const { Schema, model } = require('mongoose');

const userSchema = new Schema({
  email: { type: String, required: true, unique: true, lowercase: true },
  name:  { type: String, required: true },
  role:  { type: String, enum: ['user', 'admin'], default: 'user' },
  createdAt: { type: Date, default: Date.now },
});

const User = model('User', userSchema);
await User.create({ email: 'a@b.com', name: 'Alice' });

Mongoose enforces types, required, enum, unique (via an index), defaults, and custom validators — and can run middleware/hooks (e.g., hash a password on pre('save')).

Modeling: embed vs reference — driven by access patterns:

  • Embed related data you read together and that's bounded:
// An order with its line items embedded — fetched in one read
{ _id, userId, items: [{ sku, qty, price }], total }
  • Reference when data is large, shared, or queried independently:
const postSchema = new Schema({ author: { type: Schema.Types.ObjectId, ref: 'User' } });
const posts = await Post.find().populate('author'); // join-like lookup

Trade-offs:

  • Embedding → fewer queries, atomic updates of the whole document, but risks unbounded growth and duplication.
  • Referencing → normalized, but needs populate/lookups (watch for N+1).

Key idea: in document databases you model around how you read the data, often denormalizing for read performance — the opposite instinct from normalized SQL design.