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.
Validation
We can validate documents before saving by using the validate
method.
For example, we can write:
const { runInContext } = require('vm');
async function run() {
const mongoose = require('mongoose');
const connection = mongoose.createConnection('mongodb://localhost:27017/test');
const schema = new mongoose.Schema({ name: 'string', size: 'string' });
const Tank = connection.model('Tank', schema);
let t = new Tank({ name: 'foo', size: 'small' });
await t.validate();
let t2 = new Tank({ name: 'foo', size: -1 });
await t2.validate();
}
run();
validate
is run internally so we don’t have to run it ourselves.
We can set the runValidators
property explicitly to control whether we want to run the validator:
const { runInContext } = require('vm');
async function run() {
const mongoose = require('mongoose');
const connection = mongoose.createConnection('mongodb://localhost:27017/test');
const schema = new mongoose.Schema({ name: 'string', size: 'string' });
const Tank = connection.model('Tank', schema);
Tank.updateOne({}, { size: -1 }, { runValidators: true });
}
run();
Overwriting
We can overwrite a document.
For example, we can write:
const { runInContext } = require('vm');
async function run() {
const mongoose = require('mongoose');
const connection = mongoose.createConnection('mongodb://localhost:27017/test');
const schema = new mongoose.Schema({ name: 'string', size: 'string' });
const Tank = connection.model('Tank', schema);
const doc = await Tank.findOne({ });
doc.overwrite({ name: 'James' });
await doc.save();
}
run();
to call the overwrite
method to change the first tanks
document with the name
field set to 'James'
.
Subdocuments
Subdocuments are documents that are embedded in other documents.
We can nest schemas in other schemas.
For example, we can write:
const { runInContext } = require('vm');
async function run() {
const mongoose = require('mongoose');
const connection = mongoose.createConnection('mongodb://localhost:27017/test');
const childSchema = new mongoose.Schema({ name: 'string' });
const parentSchema = new mongoose.Schema({
children: [childSchema],
child: childSchema
});
const Child = await connection.model('Child', childSchema);
const Parent = await connection.model('Parent', parentSchema);
const parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
await parent.save();
}
run();
We created the Child
and Parent
schemas with the Child
schema embedded in the Parent
schema.
The children
property has an array of documents that fie the Child
schema.
When we call save
on the parent
, everything embedded inside will also be saved.
We can watch the validate
and save
events for each schema.
For example, we can write:
const { runInContext } = require('vm');
async function run() {
const mongoose = require('mongoose');
const connection = mongoose.createConnection('mongodb://localhost:27017/test');
const childSchema = new mongoose.Schema({ name: 'string' });
const parentSchema = new mongoose.Schema({
children: [childSchema],
child: childSchema
});
childSchema.pre('validate', function (next) {
console.log('2');
next();
});
childSchema.pre('save', function (next) {
console.log('3');
next();
});
parentSchema.pre('validate', function (next) {
console.log('1');
next();
});
parentSchema.pre('save', function (next) {
console.log('4');
next();
});
const Child = await connection.model('Child', childSchema);
const Parent = await connection.model('Parent', parentSchema);
const parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
await parent.save();
}
run();
We see that they have the number logged.
They should run in the order in the same order the numbers are in.
So first the parent is validated, then the children are validated.
The children documents are saved, and then the parent is saved.
Conclusion
Mongoose comes with document validation built-in.