MongoDB - Connecting to MongoDB with Mongoose

MongoDB - Connecting to MongoDB with Mongoose

Connecting to MongoDB with Mongoose  

Introduction

MongoDB is a NoSQL database that stores data in flexible, JSON-like documents. It is popular for its scalability and performance. When building applications with Node.js, we often use Mongoose, a MongoDB object modeling tool, to interact with MongoDB. Mongoose provides a straightforward, schema-based solution to model application data and includes built-in type casting, validation, query building, and business logic hooks.

What is Mongoose?

Mongoose is an ODM (Object Data Modeling) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB.

Why Use Mongoose?

  • Schema-based modeling.
  • Middleware support (pre and post hooks).
  • Built-in validation.
  • Powerful query building features.
  • Ease of defining relationships and referencing documents.

Installing MongoDB and Mongoose

1. Installing MongoDB

You can install MongoDB from the official website or use a cloud-based service like MongoDB Atlas.

2. Installing Mongoose via npm

To use Mongoose in a Node.js project, first initialize a project and then install Mongoose:

npm init -y
npm install mongoose

Connecting to MongoDB Using Mongoose

1. Basic Connection

The simplest way to connect to MongoDB using Mongoose is:

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydatabase', {
    useNewUrlParser: true,
    useUnifiedTopology: true
})
.then(() => console.log('MongoDB connected...'))
.catch(err => console.log(err));

Here, mydatabase is the name of the database you are connecting to. MongoDB will create the database automatically if it does not exist.

2. Understanding Connection Options

Mongoose provides connection options to fine-tune the behavior:

  • useNewUrlParser: Uses the new MongoDB connection string parser.
  • useUnifiedTopology: Opts in to using the MongoDB driver's new connection management engine.

3. MongoDB URI Formats

The connection string can also be used to connect to remote or cloud-hosted databases:

mongoose.connect('mongodb+srv://user:password@cluster0.mongodb.net/mydatabase?retryWrites=true&w=majority', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

Creating a Mongoose Schema and Model

1. Defining a Schema

In Mongoose, a schema defines the structure of the documents within a collection.

const { Schema } = mongoose;

const userSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true,
        unique: true
    },
    age: Number,
    createdAt: {
        type: Date,
        default: Date.now
    }
});

2. Creating a Model

Models are compiled from schemas. A model is a class with which we construct documents.

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

Performing CRUD Operations

1. Creating Documents

const newUser = new User({
    name: 'Alice',
    email: 'alice@example.com',
    age: 25
});

newUser.save()
    .then(user => console.log('User saved:', user))
    .catch(err => console.log('Error:', err));

2. Reading Documents

User.find()
    .then(users => console.log(users))
    .catch(err => console.log(err));

To filter records:

User.find({ age: { $gt: 20 } })
    .then(users => console.log(users));

3. Updating Documents

User.updateOne({ name: 'Alice' }, { $set: { age: 26 } })
    .then(result => console.log('Update result:', result));

4. Deleting Documents

User.deleteOne({ name: 'Alice' })
    .then(result => console.log('Deleted:', result));

Handling Connection Events

1. Listening to Events

mongoose.connection.on('connected', () => {
    console.log('Mongoose connected to DB');
});

mongoose.connection.on('error', (err) => {
    console.log('Mongoose connection error:', err);
});

mongoose.connection.on('disconnected', () => {
    console.log('Mongoose disconnected');
});

2. Graceful Shutdown

To close the Mongoose connection when the application is terminated:

process.on('SIGINT', async () => {
    await mongoose.connection.close();
    console.log('Mongoose disconnected on app termination');
    process.exit(0);
});

Using Async/Await with Mongoose

Example:

async function createUser() {
    try {
        const user = new User({ name: 'Bob', email: 'bob@example.com' });
        const savedUser = await user.save();
        console.log('Saved user:', savedUser);
    } catch (err) {
        console.error('Error:', err);
    }
}

MongoDB Atlas with Mongoose

MongoDB Atlas is a cloud-based MongoDB service. To connect Mongoose to Atlas:

  1. Create an account on MongoDB Atlas.
  2. Create a new cluster.
  3. Add your IP to the access list.
  4. Create a user and get the connection URI.

Connect using Mongoose:

mongoose.connect('mongodb+srv://user:password@cluster0.mongodb.net/mydatabase?retryWrites=true&w=majority', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

Validations in Mongoose

1. Built-in Validators

const productSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, 'Product name is required'],
        minlength: [3, 'Minimum 3 characters']
    },
    price: {
        type: Number,
        min: 0
    }
});

2. Custom Validators

const userSchema = new mongoose.Schema({
    username: {
        type: String,
        validate: {
            validator: function(v) {
                return /^[a-zA-Z0-9]+$/.test(v);
            },
            message: props => `${props.value} is not a valid username!`
        }
    }
});

Mongoose Middleware (Hooks)

1. Pre-save Hook

userSchema.pre('save', function(next) {
    this.createdAt = Date.now();
    next();
});

2. Post-save Hook

userSchema.post('save', function(doc) {
    console.log(`${doc.name} was saved.`);
});

Populating References

References allow you to normalize data across collections.

1. Defining Relationships

const postSchema = new mongoose.Schema({
    title: String,
    author: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    }
});

2. Populating Data

Post.find().populate('author')
    .then(posts => console.log(posts));

Indexes in Mongoose

1. Creating Indexes

userSchema.index({ email: 1 }, { unique: true });

Connection Pooling

Mongoose uses a connection pool to manage multiple database connections efficiently.

Configuration Example:

mongoose.connect(uri, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    poolSize: 10
});

Best Practices

  • Always handle connection errors.
  • Use environment variables to store sensitive data.
  • Use async/await instead of callbacks.
  • Validate user input before saving.
  • Use indexes to improve query performance.

Using Mongoose to connect and interact with MongoDB in Node.js applications offers a powerful and flexible way to manage data. It abstracts away the complexities of the MongoDB driver, offers schema-based data modeling, and integrates seamlessly with modern JavaScript practices. Whether you're building a simple application or a complex system with multiple data relationships, Mongoose provides all the tools necessary to structure, validate, and query your data efficiently.

Beginner 5 Hours
MongoDB - Connecting to MongoDB with Mongoose

Connecting to MongoDB with Mongoose  

Introduction

MongoDB is a NoSQL database that stores data in flexible, JSON-like documents. It is popular for its scalability and performance. When building applications with Node.js, we often use Mongoose, a MongoDB object modeling tool, to interact with MongoDB. Mongoose provides a straightforward, schema-based solution to model application data and includes built-in type casting, validation, query building, and business logic hooks.

What is Mongoose?

Mongoose is an ODM (Object Data Modeling) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB.

Why Use Mongoose?

  • Schema-based modeling.
  • Middleware support (pre and post hooks).
  • Built-in validation.
  • Powerful query building features.
  • Ease of defining relationships and referencing documents.

Installing MongoDB and Mongoose

1. Installing MongoDB

You can install MongoDB from the official website or use a cloud-based service like MongoDB Atlas.

2. Installing Mongoose via npm

To use Mongoose in a Node.js project, first initialize a project and then install Mongoose:

npm init -y npm install mongoose

Connecting to MongoDB Using Mongoose

1. Basic Connection

The simplest way to connect to MongoDB using Mongoose is:

const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('MongoDB connected...')) .catch(err => console.log(err));

Here, mydatabase is the name of the database you are connecting to. MongoDB will create the database automatically if it does not exist.

2. Understanding Connection Options

Mongoose provides connection options to fine-tune the behavior:

  • useNewUrlParser: Uses the new MongoDB connection string parser.
  • useUnifiedTopology: Opts in to using the MongoDB driver's new connection management engine.

3. MongoDB URI Formats

The connection string can also be used to connect to remote or cloud-hosted databases:

mongoose.connect('mongodb+srv://user:password@cluster0.mongodb.net/mydatabase?retryWrites=true&w=majority', { useNewUrlParser: true, useUnifiedTopology: true });

Creating a Mongoose Schema and Model

1. Defining a Schema

In Mongoose, a schema defines the structure of the documents within a collection.

const { Schema } = mongoose; const userSchema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true, unique: true }, age: Number, createdAt: { type: Date, default: Date.now } });

2. Creating a Model

Models are compiled from schemas. A model is a class with which we construct documents.

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

Performing CRUD Operations

1. Creating Documents

const newUser = new User({ name: 'Alice', email: 'alice@example.com', age: 25 }); newUser.save() .then(user => console.log('User saved:', user)) .catch(err => console.log('Error:', err));

2. Reading Documents

User.find() .then(users => console.log(users)) .catch(err => console.log(err));

To filter records:

User.find({ age: { $gt: 20 } }) .then(users => console.log(users));

3. Updating Documents

User.updateOne({ name: 'Alice' }, { $set: { age: 26 } }) .then(result => console.log('Update result:', result));

4. Deleting Documents

User.deleteOne({ name: 'Alice' }) .then(result => console.log('Deleted:', result));

Handling Connection Events

1. Listening to Events

mongoose.connection.on('connected', () => { console.log('Mongoose connected to DB'); }); mongoose.connection.on('error', (err) => { console.log('Mongoose connection error:', err); }); mongoose.connection.on('disconnected', () => { console.log('Mongoose disconnected'); });

2. Graceful Shutdown

To close the Mongoose connection when the application is terminated:

process.on('SIGINT', async () => { await mongoose.connection.close(); console.log('Mongoose disconnected on app termination'); process.exit(0); });

Using Async/Await with Mongoose

Example:

async function createUser() { try { const user = new User({ name: 'Bob', email: 'bob@example.com' }); const savedUser = await user.save(); console.log('Saved user:', savedUser); } catch (err) { console.error('Error:', err); } }

MongoDB Atlas with Mongoose

MongoDB Atlas is a cloud-based MongoDB service. To connect Mongoose to Atlas:

  1. Create an account on MongoDB Atlas.
  2. Create a new cluster.
  3. Add your IP to the access list.
  4. Create a user and get the connection URI.

Connect using Mongoose:

mongoose.connect('mongodb+srv://user:password@cluster0.mongodb.net/mydatabase?retryWrites=true&w=majority', { useNewUrlParser: true, useUnifiedTopology: true });

Validations in Mongoose

1. Built-in Validators

const productSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Product name is required'], minlength: [3, 'Minimum 3 characters'] }, price: { type: Number, min: 0 } });

2. Custom Validators

const userSchema = new mongoose.Schema({ username: { type: String, validate: { validator: function(v) { return /^[a-zA-Z0-9]+$/.test(v); }, message: props => `${props.value} is not a valid username!` } } });

Mongoose Middleware (Hooks)

1. Pre-save Hook

userSchema.pre('save', function(next) { this.createdAt = Date.now(); next(); });

2. Post-save Hook

userSchema.post('save', function(doc) { console.log(`${doc.name} was saved.`); });

Populating References

References allow you to normalize data across collections.

1. Defining Relationships

const postSchema = new mongoose.Schema({ title: String, author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } });

2. Populating Data

Post.find().populate('author') .then(posts => console.log(posts));

Indexes in Mongoose

1. Creating Indexes

userSchema.index({ email: 1 }, { unique: true });

Connection Pooling

Mongoose uses a connection pool to manage multiple database connections efficiently.

Configuration Example:

mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 10 });

Best Practices

  • Always handle connection errors.
  • Use environment variables to store sensitive data.
  • Use async/await instead of callbacks.
  • Validate user input before saving.
  • Use indexes to improve query performance.

Using Mongoose to connect and interact with MongoDB in Node.js applications offers a powerful and flexible way to manage data. It abstracts away the complexities of the MongoDB driver, offers schema-based data modeling, and integrates seamlessly with modern JavaScript practices. Whether you're building a simple application or a complex system with multiple data relationships, Mongoose provides all the tools necessary to structure, validate, and query your data efficiently.

Related Tutorials

Frequently Asked Questions for Node.js

A function passed as an argument and executed later.

Runs multiple instances to utilize multi-core systems.

Reusable blocks of code, exported and imported using require() or import.

nextTick() executes before setImmediate() in the event loop.

Starts a server and listens on specified port.

Node Package Manager β€” installs, manages, and shares JavaScript packages.

A minimal and flexible web application framework for Node.js.

A stream handles reading or writing data continuously.

It processes asynchronous callbacks and non-blocking I/O operations efficiently.

Node.js is a JavaScript runtime built on Chrome's V8 engine for server-side scripting.

An object representing the eventual completion or failure of an asynchronous operation.

require is CommonJS; import is ES6 syntax (requires transpilation or newer versions).

Use module.exports or exports.functionName.

Variables stored outside the code for configuration, accessed using process.env.


MongoDB, often used with Mongoose for schema management.

Describes project details and manages dependencies and scripts.

Synchronous blocks execution; asynchronous runs in background without blocking.

Allows or restricts resources shared between different origins.

Use try-catch, error events, or middleware for error handling.

Provides file system-related operations like read, write, delete.

Using event-driven architecture and non-blocking I/O.

Functions in Express that execute during request-response cycle.

A set of routes or endpoints to interact with server logic or databases.

Yes, it's single-threaded but handles concurrency using the event loop and asynchronous callbacks.

Middleware to parse incoming request bodies, like JSON or form data.

line

Copyrights © 2024 letsupdateskills All rights reserved