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);
}