Skip to main content

Session 04: MongoDB and Mongoose

Install MongoDB and tools

Install MongoDB driver and Mongoose

Download and install mongodb package:

npm install mongodb --save
npm install mongoose --save

Mongoose SchemaTypes

https://mongoosejs.com/docs/schematypes.html

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array
  • Decimal128
  • Map
  • Schema

Mongoose Built-in Validators

https://mongoosejs.com/docs/validation.html#built-in-validators


Create Mongoose Model

Category

const mongoose = require('mongoose');
const { Schema, model } = mongoose;

const categorySchema = new Schema({
name: { type: String, required: true },
description: String,
});

const Category = model('Category', categorySchema);
module.exports = Category;

Product

const mongoose = require('mongoose');
const { Schema, model } = mongoose;

const productSchema = new Schema({
name: { type: String, required: true },
price: { type: Number, required: true, min: 0, default: 0 },
discount: { type: Number, min: 0, max: 75, default: 0 },
stock: { type: Number, min: 0, default: 0 },
categoryId: { type: Schema.Types.ObjectId, ref: 'Category', required: true },
supplierId: { type: Schema.Types.ObjectId, ref: 'Supplier', required: true },
});

const Product = model('Product', productSchema);

module.exports = Product;

Manipulate & read data with Mongoose

Create

const { default: mongoose } = require('mongoose');
const { Category } = require('../models');

mongoose.connect('mongodb://localhost:27017/training-database');

try {
const data = {
name: 'Thời trang',
description: 'Mô tả ...',
};

const newItem = new Category(data);
newItem.save().then((result) => {
console.log(result);
});
} catch (err) {
console.log(err);
}

Update

const { default: mongoose } = require('mongoose');
const { Category } = require('../models');

mongoose.connect('mongodb://localhost:27017/training-database');

try {
const id = '63623f180b99f96759d9cc30';
const data = { name: 'New Name' };
Category.findByIdAndUpdate(id, data, {
new: true,
}).then((result) => {
console.log(result);
});
} catch (err) {
console.log(err);
}

Delete

const { default: mongoose } = require('mongoose');
const { Category } = require('../models');

mongoose.connect('mongodb://localhost:27017/training-database');

try {
const id = '6362647d5ff5a41f96d24df6';

Category.findByIdAndDelete(id).then((result) => {
console.log(result);
});
} catch (err) {
console.log(err);
}

Get all data

const { default: mongoose } = require('mongoose');
const { Category } = require('../models');

mongoose.connect('mongodb://localhost:27017/training-database');

try {
Category.find().then((result) => {
console.log(result);
});
} catch (err) {
console.log(err);
}

Get by Id

const { default: mongoose } = require('mongoose');
const { Category } = require('../models');

mongoose.connect('mongodb://localhost:27017/training-database');

try {
const id = '636263af9766a403ebf7328c';
Category.findById(id).then((result) => {
console.log(result);
});
} catch (err) {
console.log(err);
}

Mongoose Virtuals

info

In Mongoose, a virtual is a property that is not stored in MongoDB. Virtuals are typically used for computed properties on documents.

First virtual

productSchema.virtual('total').get(function () {
return (this.price * (100 - this.discount)) / 100;
});

Virtuals in JSON

info

By default, Mongoose does not include virtuals when you convert a document to JSON. For example, if you pass a document to Express' res.json() function, virtuals will not be included by default.

To include virtuals in res.json(), you need to set the toJSON schema option to { virtuals: true }.

Example:

productSchema.set('toJSON', { virtuals: true });

const Product = model('Product', productSchema);
module.exports = Product;

Virtuals in console.log()

// Virtuals in console.log()
productSchema.set('toObject', { virtuals: true });

const Product = model('Product', productSchema);
module.exports = Product;

Virtuals with Lean

info

Virtuals are properties on Mongoose documents. If you use the lean option, that means your queries return POJOs (Plain old Javascript object) rather than full Mongoose documents. That means no virtuals if you use lean().

Ref: https://plugins.mongoosejs.io/plugins/lean-virtuals

Setup

const mongooseLeanVirtuals = require('mongoose-lean-virtuals');

Create s schema

const userSchema = new mongoose.Schema({ name: String });

userSchema.virtual('lowercase').get(function () {
return this.name.toLowerCase();
});

Apply plugin

userSchema.plugin(mongooseLeanVirtuals);

Later

You must pass virtuals: true to lean(), otherwise lowercase won't be in res

const res = await UserModel.find().lean({ virtuals: true });

Limitations of virtuals

caution

Mongoose virtuals are not stored in MongoDB, which means you can't query based on Mongoose virtuals.

Virtuals with Populate

Mongoose also supports populating virtuals. A populated virtual contains documents from another collection. To define a populated virtual, you need to specify:

  • The ref option, which tells Mongoose which model to populate documents from.
  • The localField and foreignField options. Mongoose will populate documents from the model in ref whose foreignField matches this document's localField.
// Virtual with Populate
productSchema.virtual('category', {
ref: 'Category',
localField: 'categoryId',
foreignField: '_id',
justOne: true,
});
try {
Product.find({})
.populate('category')
.then((result) => {
console.log(result);
});
} catch (err) {
console.log(err);
}