To make MongoDB database manipulation easy, we can use the Mongoose NPM package to make working with MongoDB databases easier.
In this article, we’ll look at how to use Mongoose to manipulate our MongoDB database.
Update Validators Only Run On Updated Paths
We can add validators to run only on updated paths.
For instance, we can write:
async function run() {
const { createConnection, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const kittenSchema = new Schema({
name: { type: String, required: true },
age: Number
});
const Kitten = connection.model('Kitten', kittenSchema);
const update = { color: 'blue' };
const opts = { runValidators: true };
Kitten.updateOne({}, update, opts, (err) => {
console.log(err)
});
const unset = { $unset: { name: 1 } };
Kitten.updateOne({}, unset, opts, (err) => {
console.log(err);
});
}
run();
then only the second updateOne
callback will have its err
parameter defined because we unset the name
field when it’s required.
Update validators only run on some operations, they include:
$set
$unset
$push
(>= 4.8.0)$addToSet
(>= 4.8.0)$pull
(>= 4.12.0)$pullAll
(>= 4.12.0)
Middleware
Middlewares are functions that are passed control during the execution of async functions.
They are useful for writing plugins.
There are several types of middleware. They include:
validate
save
remove
updateOne
deleteOne
init
(init hooks are synchronous)
Query middleware are supported for some model and query functions. They include:
count
deleteMany
deleteOne
find
findOne
findOneAndDelete
findOneAndRemove
findOneAndUpdate
remove
update
updateOne
updateMany
Aggregate middleware is for the aggregate
method.
They run when we call exec
on the aggregate object.
Pre Middleware
We can one or more pre middleware for an operation.
They are run one after the other by each middleware calling next
.
For example, we can write:
async function run() {
const { createConnection, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const kittenSchema = new Schema({
name: { type: String, required: true },
age: Number
});
kittenSchema.pre('save', (next) => {
next();
});
const Kitten = connection.model('Kitten', kittenSchema);
}
run();
to add a pre middleware for the that runs before the save operation.
Once the next
function is run, the save operation will be done.
We can also return a promise in the callback instead of calling next
in Mongoose version 5 or later.
For example, we can write:
const { captureRejectionSymbol } = require('events');
async function run() {
const { createConnection, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const kittenSchema = new Schema({
name: { type: String, required: true },
age: Number
});
kittenSchema.pre('save', async () => {
return true
});
const Kitten = connection.model('Kitten', kittenSchema);
}
run();
If we call next
in our callback, calling next
doesn’t stop the rest of the middleware code from running.
For example, if we have:
async function run() {
const { createConnection, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const kittenSchema = new Schema({
name: { type: String, required: true },
age: Number
});
kittenSchema.pre('save', async () => {
if (true) {
console.log('calling next');
next();
}
console.log('after next');
});
const Kitten = connection.model('Kitten', kittenSchema);
}
run();
Then both console logs will be displayed.
We should add return
to stop the code below the if
block from running:
async function run() {
const { createConnection, Schema } = require('mongoose');
const connection = createConnection('mongodb://localhost:27017/test');
const kittenSchema = new Schema({
name: { type: String, required: true },
age: Number
});
kittenSchema.pre('save', async () => {
if (Math.random() < 0.5) {
console.log('calling next');
return next();
}
console.log('after next');
});
const Kitten = connection.model('Kitten', kittenSchema);
}
run();
Conclusion
We can add middleware for various operations to run code before them.