Mongoose is a popular Object Data Modeling (ODM) library for MongoDB in Node.js. It provides an easy way to work with MongoDB by abstracting the database interactions into a higher level API. On the other hand, TypeScript is a strongly-typed superset of JavaScript that provides static type checking at compile-time, making it easier to write robust and maintainable code. In this tutorial, we will explore how to use Mongoose with TypeScript to build a scalable and maintainable application.
Prerequisites
Before we get started, make sure you have the following installed on your system:
- Node.js and npm
- MongoDB
- TypeScript (npm install -g typescript)
Setting up a TypeScript project
Let's start by setting up a basic TypeScript project. Create a new directory and run npm init to initialize a new Node.js project. Then, install the required dependencies:
npm install --save mongoose @types/mongoosemongoose is the main library we will be using, and @types/mongoose provides the TypeScript type definitions for the library.
Next, create a tsconfig.json file in the root of your project directory:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "dist",
"sourceMap": true,
"esModuleInterop": true
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}This file configures the TypeScript compiler to output ES6-style JavaScript code into the dist directory, with source maps for easy debugging. It also includes any .ts files in the src directory and excludes the node_modules directory.
Create a src directory in the root of your project directory and create a new index.ts file inside it:
console.log('Hello, world!');Now, run tsc to compile your TypeScript code into JavaScript:
tsc
This should generate a dist/index.js file. You can now run this file with node dist/index.js, and you should see the "Hello, world!" message in your console.
Connecting to MongoDB with Mongoose
Now that we have our TypeScript project set up, let's start using Mongoose to interact with MongoDB. Create a new file in the src directory called db.ts:
import mongoose from 'mongoose';
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false
}).then(() => {
console.log('Connected to MongoDB');
}).catch((err) => {
console.error('Error connecting to MongoDB', err);
});In this file, we import mongoose and connect to a local MongoDB database named myapp. We also pass some options to the connect method to configure the connection. If the connection is successful, we log a message to the console. If there is an error, we log the error message to the console.
To use this file, we need to import it in our index.ts file and run it before anything else:
import './db';
console.log('Hello, world!');
Now, when you run node dist/index.js, you should see the "Connected to MongoDB" message in your console.
Defining a Mongoose schema
Now that we have connected to MongoDB, let's define a Mongoose schema to represent a user object. Create a new file in the src directory called user.ts:
import mongoose from 'mongoose';
export interface User {
firstName: string;
lastName: string;
email: string;
password: string;
}
export const userSchema = new mongoose.Schema<User>({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
In this file, we define a User interface that represents the shape of our user object. We also define a userSchema that uses the mongoose.Schema constructor to define the fields of our user object. The required option indicates that these fields are mandatory, and the unique option ensures that each email address is unique.
Creating a Mongoose model
With our schema defined, let's create a Mongoose model that uses this schema to interact with our MongoDB database. Create a new file in the src directory called userModel.ts:
import mongoose from 'mongoose';
import { userSchema, User } from './user';
export const UserModel = mongoose.model<User>('User', userSchema);In this file, we import our userSchema and User interface from the user.ts file. We also use the mongoose.model method to create a new model called UserModel that uses our schema and represents a collection of User objects in our database.
Using the Mongoose model
Now that we have our Mongoose model, let's use it to perform some CRUD operations on our MongoDB database. Update the index.ts file to create a new user, find all users, and update a user:
import './db';
import { UserModel } from './userModel';
async function run() {
// Create a new user
const newUser = await UserModel.create({
firstName: 'John',
lastName: 'Doe',
email: 'johndoe@example.com',
password: 'password123'
});
console.log('Created user:', newUser);
// Find all users
const allUsers = await UserModel.find();
console.log('All users:', allUsers);
// Update a user
const updatedUser = await UserModel.findOneAndUpdate(
{ email: 'johndoe@example.com' },
{ firstName: 'Jane' },
{ new: true }
);
console.log('Updated user:', updatedUser);
}
run().catch((err) => {
console.error(err);
});In this file, we import our UserModel and use it to create a new user, find all users, and update a user. The create method takes a User object and inserts it into the database. The find method returns all users in the database. The findOneAndUpdate method finds a user with a given email address and updates their first name. The new: true option tells Mongoose to return the updated user object.
Conclusion
In this tutorial, we explored how to use Mongoose with TypeScript to build a scalable and maintainable application. We defined a Mongoose schema to represent a user object, created a Mongoose model that uses this schema to interact with our MongoDB database, and used this model to perform CRUD operations on our database. By using TypeScript, we were able to write robust and maintainable code that catches errors at compile-time and makes our code easier to understand and reason about.