MongoDB

MongoDB is a NoSQL database that stores data in JSON-like documents (called BSON - Binary JSON). Unlike traditional SQL databases, MongoDB does not use tables and rows; instead, it uses collections and documents.

Key Features:

    • Schema-less: You can store different fields in each document.
    • Scalable: Designed for horizontal scalability via sharding.
    • High Performance: Fast reads/writes with indexes and memory usage.
    • Aggregation Framework: Similar to SQL GROUP BY.
    • Replication: Data redundancy using replica sets.
    • Ad-hoc Queries: Rich query language with support for filtering and projections.

BSON

BSON (Binary JSON) is a binary-encoded serialization format used by MongoDB to store and exchange data. It extends JSON to provide additional data types and efficient storage, making it ideal for MongoDB's document-oriented database.


we provide data to MongoDB in JSON-like syntax (actually JavaScript objects in the shell or JSON in drivers), but… MongoDB automatically converts that data into BSON internally when storing it.

mongosh (Mongo Shell):

mongosh (MongoDB Shell) is a modern command-line tool for interacting with MongoDB databases.

Modern JavaScript Support: Built on Node.js, supports ES6+ features (e.g., async/await, arrow functions). Interactive REPL: Provides a JavaScript-based environment for querying and managing MongoDB databases.

To start mongosh use: mongosh

Then use commands example: show dbs // Show all databases use mydb // Create/switch to database show collections // List collections e.t.c.

Document & Collections

In MongoDB, documents and collections are core components of its data model, used to store and organize data in a NoSQL, document-oriented database.

Document

A document is the basic unit of data in MongoDB. It's similar to a row in a SQL table. Stored in BSON Format. Contains key-value pairs. Each document has a unique _id field (like a primary key).

Structure: Documents are composed of fields (keys) and values, where values can be strings, numbers, arrays, nested documents, or special types like ObjectId, Date, or Binary.

Flexibility: Each document in a collection can have a different structure (no fixed schema).

Example: {   "_id": ObjectId("507f1f77bcf86cd799439011"),   "name": "Alice",   "age": 25,   "address": {     "city": "New York",     "country": "USA"   },   "hobbies": ["reading", "gaming"],   "createdAt": ISODate("2025-06-24T15:23:00Z") } _id: A unique identifier (auto-generated if not provided)

Collection

A collection is a group of documents. Similar to a table in SQL. You don't need to define a fixed schema. Each document inside a collection can have a different structure. Created automatically when you insert your first document.

Naming: Collections are identified by a name (e.g., users, products). Names are case-sensitive and should avoid special characters.

Example - A collection named users may contain: // Document 1 { name: "Inderjit", age: 20 } // Document 2 { name: "Doe", email: "doe@gmail.com", hobbies: ["music", "yoga"] } // Document 3 { name: "John", isActive: false, city: "Delhi" }

Insert in MongoDB

To insert data into a MongoDB database using mongosh, you can use methods like insertOne() for a single document or insertMany() for multiple documents.

Steps to Insert Data - 1. Connect to MongoDB, 2. Select a Database, 3. Insert into a Collection.

insertOne

The insertOne() method in MongoDB is used to insert a single document into a collection.

Syntax:

db.collection_name.insertOne({ document })

collection_name: Name of the collection (automatically created if not present).

document: A single JavaScript object or JSON-like document.

Example: db.students.insertOne({   name: "Inderjit",   age: 20,   course: "CSE" }); //This will create a document like: {   _id: ObjectId("66a93d...."),   name: "Inderjit",   age: 20,   course: "CSE" } _id: A unique identifier (auto-generated if not provided) //we can also use our custom id while inserting like _id: "stu001" //collection(named students here) is automatically created if not there

insertMany

insertMany() is used to insert multiple documents into a MongoDB collection at once.

Syntax:

db.collection_name.insertMany([ { doc1 }, { doc2 }, ... ])

Example: db.students.insertMany([   { name: "Inderjit", age: 20, city: "Ludhiana" },   { name: "john", age: 22, city: "Delhi" },   { name: "Smith", age: 24, city: "Amritsar" } ]);

There are other methods also to insert...

Insert in MongoDB

MongoDB provides a method called find() to query and view documents inside a collection.

find()

Syntax:

db.collection.find()

This displays all documents in the specified collection.

Example: db.students.find() Output like: { _id: ObjectId("66a950..."), name: "Inderjit", age: 20 } { _id: ObjectId("66a951..."), name: "John", age: 22 }

find({ key: value })

Returns all documents that match the given key-value condition.

It returns a cursor object — not the actual documents directly. You can iterate over the cursor to access documents.

Syntax:

db.collection.find({ key: value })

Example: db.students.find({ age: 20 }) //Returns all students with age = 20 //OR multiple conditions: db.students.find({ age: 20, city: "jalandhar" }) //Returns all students with age = 20 AND city = jalandhar

find({ key: value })

Returns only the first document that matches the condition.

It returns a single document object. If no match is found, it returns null.

Syntax:

db.collection.findOne({ key: value })

Example: db.students.findOne({ age: 20 }) //Returns only the first match with age = 20 //OR multiple conditions: db.students.find({ age: 20, city: "jalandhar" }) //Returns all students with age = 20 AND city = jalandhar

find().pretty()

This formats the output to make it more readable.

Syntax:

db.collection.find().pretty()

Example: db.students.find().pretty() Output like: {   "_id" : ObjectId("66a950..."),   "name" : "Inderjit",   "age" : 20 } {   "_id" : ObjectId("66a951..."),   "name" : "John",   "age" : 22 }

There are other methods also...

Query Operators

Query operators in MongoDB allow you to filter data using conditions like greater than, less than, not equal, matching arrays, etc. Used inside find() or findOne() to make powerful queries.

1. Comparison Operators

Match values based on comparisons.

$eq

Matches values equal to the specified value.

Example: db.users.find({ age: { $eq: 25 } }) //Output: Documents where age is exactly 25

$ne

Matches values not equal to the specified value.

Example: db.users.find({ status: { $ne: "active" } }) //Output: Documents where status is not "active"

$gt, $gte

$gt - Greater than, $gte - greater than or equa

Example: db.users.find({ age: { $gt: 25 } }) //Output: Documents where age > 25

$lt, $lte

$lt - Less than, $lte - less than or equal.

Example: db.users.find({ age: { $lte: 28 } }) //Output: Documents where age <= 28

$in

Matches any value in an array.

Example: db.users.find({ name: { $in: ["Alice", "Bob"] } }) //Output: Documents where name is "Alice" or "Bob"

$nin

Matches any value in an array.

Example: db.users.find({ name: { $nin: ["Alice", "Bob"] } }) //Output: Documents where name is neither "Alice" nor "Bob"

2. Logical Operators

Combine multiple conditions using logical expressions like AND, OR, NOT, NOR.

$and

Returns documents that match all specified conditions.

Example: db.users.find({ $and: [ { age: { $gt: 20 } }, { status: "active" } ] }) //Output: Documents where age > 20 AND status is "active"

$or

Returns documents that match at least one of the conditions.

Example: db.users.find({ $or: [ { age: 25 }, { status: "inactive" } ] }) //Output: Documents where age is 25 OR status is "inactive"

$not

Returns documents that do not match the condition.

Example: db.users.find({ age: { $not: { $gt: 30 } } }) //Output: Documents where age is NOT greater than 30

$nor

Returns documents that match none of the specified conditions.

Example: db.users.find({ $nor: [ { age: 25 }, { status: "active" } ] }) //Output: Documents where age is NOT 25 AND status is NOT "active"

There are other types of operators also like Element, Array, Evaluation, Geospatial, Bitwise Operators...

Update in DB

In MongoDB, you can update documents in a database using methods like updateOne(), updateMany(), or replaceOne().

updateOne()

Updates only the first document that matches the filter condition.

Syntax:

db.collection.updateOne( { filter }, { update }, { options } )

  • filter - The condition to find the document
  • update - The update operation
  • options(Optional) - Can include { upsert: true } to insert if not found

Example: db.users.updateOne( { name: "Inderjit" }, { $set: { age: 21 } } ) //Only the first user document with name "Inderjit" will have their age updated to 21

updateMany()

Updates all documents that match the filter condition.

Same syntax as above.

Example: db.users.updateMany( { status: "inactive" }, { $set: { status: "active" } } ) //Every document with status: "inactive" will be updated to "active"

replaceOne()

Replaces the entire first matching document (except _id) with a new one.

Syntax:

db.collection.replaceOne( { filter }, { replacement_document } )

replacement_document - You must provide the full new document (excluding _id) — anything not included will be deleted from that document.

Example: db.users.replaceOne(   { name: "Inderjit" },   { name: "Inderjit", age: 21, city: "Amritsar" } ) //Replaces the matched document completely. Any fields not in the replacement will be deleted (except _id, it will remain same).

Update and Aggregation Opertators

$set

Add a new field or update an existing field.

Example: db.users.updateOne( { name: "Inderjit" }, { $set: { age: 20 } } ) // Adds or updates the "age" field to 20

$unset

Remove a field from the document.

Example: db.users.updateOne( { name: "Inderjit" }, { $unset: { phone: "" } } ) //Removes the "phone" field from the document

$inc

Increment (or decrement) a numeric field.

Example: db.users.updateOne( { name: "Inderjit" }, { $inc: { views: 1 } } ) //Increases the "views" field by 1

$addFields (Aggregation)

Add new fields in aggregation pipeline.

Example: db.users.aggregate([ { $addFields: { isAdult: { $gte: ["$age", 18] } } } ]) // Adds "isAdult": true/false based on age

$project (Aggregation)

Include/exclude fields in aggregation output.

Example: db.users.aggregate([ { $project: { name: 1, age: 1, _id: 0 } } ]) // Shows only "name" and "age", hides "_id"

$replaceRoot (Aggregation)

Replace the current document with a subdocument.

Example: db.users.aggregate([ { $replaceRoot: { newRoot: "$profile" } } ]) // Replaces each document with the "profile" subdocument

$replaceWith (Aggregation)

Same as $replaceRoot, but more flexible.

Example: db.users.aggregate([ { $replaceWith: "$profile" } ]) // Same effect as $replaceRoot: replaces doc with "profile"

Syntax:

replacement_document - You must provide the full new document (excluding _id) — anything not included will be deleted from that document.

Example: db.users.replaceOne(   { name: "Inderjit" },   { name: "Inderjit", age: 21, city: "Amritsar" } ) //Replaces the matched document completely. Any fields not in the replacement will be deleted (except _id, it will remain same).

There are other methods to update in DB...

Delete in DB

In MongoDB, you can delete documents from a database using methods like deleteOne() and deleteMany().

deleteOne()

Deletes only the first document that matches the filter.

Syntax:

db.collection.deleteOne(filter, options)

  • filter - The condition to find the document
  • options - Optional settings, such as: writeConcern

Example: db.users.deleteOne({ name: "Inderjit" }) //Deletes the first document with name: "Inderjit"

deleteMany()

Deletes all documents that match the given filter condition.

Same syntax as above.

Example: db.users.deleteMany({ status: "inactive" }) //Deletes all users with status: "inactive".
deleteMany({}) — Delete All Docs (Not Collection) Example: db.users.deleteMany({}) //Deletes all data from users, but keeps the collection.

drop() — Drop Entire Collection

Deletes the entire collection and its documents.

Syntax:

db.collection_name.drop()

Example: db.users.drop() //Deletes users collection permanently.

dropDatabase() — Drop Entire Database

Deletes the entire current database, including all collections.

Syntax:

db.dropDatabase()

Example: //first select that database which you want to delete use shopDB db.dropDatabase() //Deletes shopDB with all its collections.

Mongoose

Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It provides a schema-based solution to model your application data and includes built-in type casting, validation, query building, and business logic hooks.

Key Features of Mongoose:

  • Schema Definition: Define structured schemas for your MongoDB collections.
  • Validation: Built-in validation for data integrity.
  • Middleware: Hooks for pre- and post-save operations.
  • Query Building: Simplifies MongoDB queries with a fluent API.
  • Population: Easily reference related documents (like JOINs in SQL).

Setup:

Install Mongoose - npm install mongoose
Connect to MongoDB using Mongoose: const mongoose = require('mongoose'); //require it // Use the async function to connect and handle errors main()   .catch((err) => {   console.log("Connection error:", err); }); async function main() {   // Try to connect   await mongoose.connect("mongodb://127.0.0.1:27017/test"); }
  • mongoose.connect(...) - This function connects your Node.js app to a MongoDB database using Mongoose.
  • mongodb:// (Protocol) -> tells Mongoose to use the MongoDB connection
  • 127.0.0.1 (Host) —> this is the localhost IP address (means MongoDB is running on your own computer)
  • 27017 (Port) -> this is the default port MongoDB runs on
  • /test (Database name) —> this tells Mongoose to connect to the test database (it will be created if it doesn't exist)

Schema

In Mongoose, a schema defines the structure of documents within a MongoDB collection (like blueprint for each document). It specifies fields, their data types, validation rules, and other constraints. Schemas are used to create models, which allow you to interact with the database.

// Exampls - Define a schema const userSchema = new mongoose.Schema({   name: { type: String, required: true },   age: Number,   email: { type: String, unique: true },   createdAt: { type: Date, default: Date.now } }); //also String is shorthand of {type: String}
Example - Nested Schemas: const addressSchema = new mongoose.Schema({   street: String,   city: String }); const userSchema = new mongoose.Schema({   name: String,   address: addressSchema });

Common Mongoose Schema Types

Data Type Description Example
String Text/string data name: String
Number Integer or float age: Number
Boolean true or false isActive: Boolean
Date Stores date and time createdAt: Date
Buffer Binary data (e.g., images/files) avatar: Buffer
ObjectId References another document userId: mongoose.Schema.Types.ObjectId
Array List of any type tags: [String]
Mixed Any type (not strict) anyField: mongoose.Schema.Types.Mixed
Map Key-value pairs with same type values meta: Map
Decimal128 High-precision decimal (money, etc.) price: mongoose.Schema.Types.Decimal128
Example Schema Using most Types: const userSchema = new mongoose.Schema({   name: String,   age: Number,   email: { type: String, required: true },   isActive: Boolean,   createdAt: { type: Date, default: Date.now },   profilePic: Buffer,   role: { type: mongoose.Schema.Types.ObjectId, ref: 'Role' }, // foreign key   tags: [String],   extraInfo: mongoose.Schema.Types.Mixed,   stats: { type: Map, of: Number },   salary: mongoose.Schema.Types.Decimal128 });

Models

A Model in Mongoose is a constructor function created from a Schema. It represents a collection in your MongoDB database and provides an interface to interact with the documents (records) in that collection.

Syntax:

const ModelName = mongoose.model('CollectionName', schemaName);

'CollectionName': Mongoose auto-pluralizes and makes it lowercase (e.g., 'User' → users collection).

Generelly we take same ModelName and CollectionName.

// Example const User = mongoose.model('User', userSchema);

Insert using Mongoose

Mongoose provides several methods to insert documents into a MongoDB collection using a model. Below, are the primary methods for inserting data.

In Mongoose insert methods, an _id is automatically assigned to every document by default, unless you manually specify one.

First Connect to database and Define a schema and model then:

1. new and .save()

Create a new document instance and save it to the database.

// Example const newUser = new User({   name: 'Alice',   age: 25,   email: 'alice@example.com' }); newUser.save() //it writes it to MongoDB   .then(user => console.log('User saved:', user))   .catch(err => console.error('Error:', err)); //.save() Returns a promise with the created document. //When to use: Best for single document creation, Good for validation and middleware

2. Model.create()

Insert one or multiple documents directly.

// Example - Insert Single document User.create({   name: 'Bob',   age: 30,   email: 'bob@example.com' })   .then(user => console.log('User created:', user))   .catch(err => console.error('Error:', err));
// Insert Multiple documents User.create([   { name: 'Charlie', age: 28, email: 'charlie@example.com' },   { name: 'Diana', age: 22, email: 'diana@example.com' } ])   .then(users => console.log('Users created:', users))   .catch(err => console.error('Error:', err)); //When to use: Convenient for quick inserts, especially for multiple documents. //Note: Returns a promise with the created document(s) and triggers validation/middleware.

3. Model.insertMany()

Insert multiple documents efficiently in a single operation.

// Example User.insertMany([   { name: 'Eve', age: 35, email: 'eve@example.com' },   { name: 'Frank', age: 40, email: 'frank@example.com' } ])   .then(users => console.log('Users inserted:', users))   .catch(err => console.error('Error:', err)); //also returns promise //When to use: Optimized for bulk inserts, faster than multiple .create() calls. //Note: By default, stops on the first error unless { ordered: false } is specified to continue inserting valid documents.

There may other ways also to insert...

Operation Buffering in Mongoose

Mongoose buffers operations (like Model.create(), Model.find(), or document.save()) if the MongoDB connection isn't ready (e.g., the database is still connecting). Once the connection is established, Mongoose executes the buffered operations in the order they were queued.

Find using Mongoose

Mongoose provides several methods to query documents in a MongoDB collection using a model. These methods allow you to retrieve data based on criteria, sort results, limit fields, and more. Below, are the primary methods for finding data.

They return a Query object, not the actual user array. The actual data comes after the query executes (with .then() or await).
Mongoose queries are "thenable" — meaning they behave like promises, even though they are not full Promise objects internally.

1. find()

Fetches all documents that match the given query criteria. Returns an array of matching documents (or an empty array if no matches are found).

Syntax:

Model.find(query, [projection], [options])

  • Model: model name
  • query: An object specifying the search criteria (e.g., { age: { $gte: 18 } })
  • projection (optional): Specifies which fields to include/exclude (e.g., { name: 1, _id: 0 })
  • options (optional): Additional query options (e.g., { sort: { age: -1 }, limit: 10 })

// Example - Find all users aged 18 or older User.find({ age: { $gte: 18 } })   .then(users => console.log('Users:', users))   .catch(err => console.error('Error:', err));

2. Model.findOne()

Retrieves the first document that matches the provided query criteria. Returns a single document or null if no match is found.

Syntax - same as above

// Example - Find the first user with a specific email User.findOne({ email: "alice@example.com" })   .then(user => console.log('User:', user || 'Not found'))   .catch(err => console.error('Error:', err));

3. Model.findById()

Retrieves a single document by its _id field (MongoDB's unique ObjectID). Returns a single document or null if no match is found.

Syntax - same as above, just at place of query id of object

// Find a user by their _id User.findById("507f1f77bcf86cd799439011")   .then(user => console.log('User:', user || 'Not found'))   .catch(err => console.error('Error:', err));

There may other ways also to find...

Update using Mongoose

You can update documents in MongoDB using Mongoose with several methods, primarily updateOne(), updateMany(), findByIdAndUpdate() and findOneAndUpdate() e.t.c.

1. updateOne()

Updates first matching document that matches your filter.

Does not return the updated document.

Syntax:

Model.updateOne(filter, update, options)

User.updateOne({ email: "test@example.com" }, { $set: { name: "Inderjit" } });

2. updateMany()

Updates all documents that matches filter condition. Syntax same as above.

Does not return the updated documents.

User.updateMany({ role: "guest" }, { $set: { active: false } });

3. findOneAndUpdate()

This method finds the first matching document, updates it, and returns the document.

Syntax - same as above.

User.findOneAndUpdate({ email: "a@b.com" }, { name: "Ajay" }, { new: true }); //setting new = true returns new updated document.

4. findByIdAndUpdate()

This is a convenient shorthand for findOneAndUpdate(). It works exactly the same way but uses the document's unique _id as the filter.

Syntax - same as above just id at place of query.

Return Value: Same as findOneAndUpdate(). It returns the document (original by default, updated if { new: true } is set) or null if the ID doesn't exist.

User.findByIdAndUpdate("64d3...f6", { age: 22 }, { new: true });

There may other ways also to update...

Delete using Mongoose

Here are the different methods to delete documents in Mongoose, each with its specific use case:

1. deleteOne()

Deletes first matching document that matches your query.

Return Value: An object confirming the operation, like { acknowledged: true, deletedCount: 1 }. It does not return the deleted document.

Syntax:

Model.deleteOne(query)

User.deleteOne({ email: "test@example.com" })   .then(result => console.log(result))   .catch(err => console.error(err));

2. deleteMany()

Deletes all documents that match the query. Syntax - same as above.

Return Value: An object confirming the operation, like { acknowledged: true, deletedCount: 5 }, where deletedCount is the number of documents removed.

User.deleteMany({ role: "guest" })   .then(result => console.log(result))   .catch(err => console.error(err));

3. findByIdAndDelete()

This is a convenient method to find a document by its unique _id and delete it.

Unlike the others, this method returns the document that was deleted or null if no document was found with that ID. Syntax - same as above just id at place of query.

User.findByIdAndDelete("64e4...abc")   .then(deletedDoc => console.log(deletedDoc))   .catch(err => console.error(err));

4. findOneAndDelete()

Finds the first matching document and deletes it.

Return Value: The deleted document object, or null if no document matched the query condition.

Syntax:

Model.findOneAndDelete(filter, options)

options (optional)

User.findOneAndDelete({ email: "user@example.com" })   .then(deletedDoc => console.log(deletedDoc))   .catch(err => console.error(err));

There may other ways also to delete...

Schema Validations

Mongoose schema validations are rules defined in the schema to ensure that documents meet specific criteria before being saved to the MongoDB database. If a document violates these rules, Mongoose throws a ValidationError and prevents the operation.

Some Validators/ Options

Validator / Option Description Data Types Example Usage
required Field is mandatory All { type: String, required: true }
default Sets a default value if none is provided All { type: Boolean, default: true }
unique Creates a unique index in MongoDB (not a real validator) All { type: String, unique: true }
minlength Minimum string length String { type: String, minlength: 5 }
maxlength Maximum string length String { type: String, maxlength: 50 }
min Minimum numeric or date value Number, Date { type: Number, min: 18 } or { type: Date, min: '2022-01-01' }
max Maximum numeric or date value Number, Date { type: Number, max: 100 }
match Value must match given regular expression String { type: String, match: /.+\@.+\..+/ }
enum Value must be one of a fixed set String, Number { type: String, enum: ['admin', 'user', 'guest'] }
validate Custom sync or async validator function All { type: Number, validate: { validator: v => v % 2 === 0, message: props => `${props.value} is not even!`} }
immutable Prevents changes once value is set All { type: String, immutable: true }
alias Creates a virtual alias for a field All { type: String, alias: 'nickname' }
select Whether the field is included by default in queries All { type: String, select: false }
get / set Transforms value on get/set All { type: Number, get: v => Math.round(v) }
lowercase Converts string to lowercase automatically String { type: String, lowercase: true }
uppercase Converts string to uppercase automatically String { type: String, uppercase: true }
trim Trims whitespace from both ends of a string String { type: String, trim: true }
There may be others also...
const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({   name: {     type: String,     required: true, // must be present     minlength: 3, // at least 3 characters     maxlength: 50 // max 50 characters   },   email: {     type: String,     required: true,     unique: true, // must be unique (index-level)     match: /.+\@.+\..+/ // basic email format   },   password: {     type: String,     required: true,     minlength: 6 // minimum 6 characters   },   age: {     type: Number,     min: 18, // must be at least 18     max: 60 // no older than 60   },   role: {     type: String,     enum: ['admin', 'user', 'guest'], // only allowed values     default: 'user'   },   isActive: {     type: Boolean,     default: true // true if not specified   },   createdAt: {     type: Date,     default: Date.now // current timestamp   },   phone: {     type: String,     validate: {     validator: function (v) {       return /^\d{10}$/.test(v); // must be a 10-digit number     },     message: props => `${props.value} is not a valid 10-digit phone number!`   },     required: true   } }); const User = mongoose.model('User', userSchema);

Validators with Custom Error Messages

Syntax:

validatorName: [value, 'Custom error message']

This format works for most built-in validators like min, max, minlength, maxlength, match, enum.

example: age: {   type: Number,   min: [18, 'Age must be at least 18'] } role: {   type: String,   enum: {     values: ['admin', 'user', 'guest'],     message: 'Role must be admin, user, or guest'   } } //Use { values: [...], message: '...' } for enum.
user.save()   .then(() => console.log('Saved!'))   .catch(err => {     console.log(err.errors.age.message); // Access the custom error message something like this });

Validation on Update Operations

By default, Mongoose does NOT run validators on update operations like: updateOne(), updateMany(), findByIdAndUpdate(), findOneAndUpdate() e.t.c.

To Enable Validation on Updates You must explicitly enable validation using the option - { runValidators: true }

example: const userSchema = new mongoose.Schema({   age: {     type: Number,     min: [18, 'Age must be at least 18']   } }); const User = mongoose.model('User', userSchema); //while updating User.findByIdAndUpdate(   '64e4abc...', // some _id   { age: 10 },   { runValidators: true})   .then(user => console.log('Updated:', user))   .catch(err => console.log('Validation Error:', err.errors.age.message)); //Without runValidators: true, the invalid value will be silently accepted //Always include runValidators: true in update operations if you want schema rules enforced.