Realtionship
By Reference(Normalization)
- Easier to maintain data consistency
- Only need to update 1 document if value changes
let author = {
_id:"11223344",
name:"James Peterson"
}
let course = {
_id:"55667788",
title:"Intro to Javascript",
authors:["11223344"]
}
By Embedded(Denormalization)
- Faster performance
- Need to Update all related documents when value changes
let course = {
_id:"55667788",
title:"Intro to Javascript",
authors:[{_id:"11223344",name:"James Peterson"}]
}
Hybrid
- Snapshot of data at a point in time
- e.g. an order has price of product at that time
let author = {
_id:"11223344",
name:"James Peterson",
DOB:"1980-10-12",
...other properties
}
let course = {
_id:"55667788",
title:"Intro to Javascript",
authors:[{_id:"11223344",name:"James Peterson"}]
}
Modeling by Reference
const authorSchema = new mongoose.Schema({
name:String,
bio:String,
website:String
});
const Author = new mongoose.model('Author',authorSchema);
const courseSchema = new mongoose.Schema({
title:String,
author:{type:mongoose.Schema.Types.ObjectId,ref:'Author'} //this references the author document by its _id
});
const Course = mongoose.model('Course',courseSchema);
Populate method
- reference documents in other collections
const listCourses = async () =>{
const courses = await Course.find().populate('author') //mongoose will get all the author details using the objectId
res.send(result);
}
const listCourses = async () =>{
const result = await Course.find().populate('author', 'name') //mongoose will only get author name
res.send(result);
}
Modeling by Embedded
const authorSchema = new mongoose.Schema({
name:String,
bio:String,
website:String
});
const Author = new mongoose.model('Author',authorSchema);
const courseSchema = new mongoose.Schema({
title:String,
author: authorSchema //this embeds the author inside courseSchema
});
const Course = mongoose.model('Course',courseSchema);
add array of subdocument
const Course = mongoose.model("course", new mongoose.Schema({
title:String,
authors:[authorSchema]
}));
const createCourse = async (title, authors) =>{
const course = new Course({title,authors});
const result = await course.save();
console.log(result);
}
createCourse("NodeJS Course", [new Author({name:"Peter"}),new Author({name:"James"})]);
const addAuthor = async (courseId,author){
const course = await Course.findById(courseId);
course.authors.push(author);
course.save();
}
addAuthor("6234125asdf25c554werw87", new Author({name:"Janet"}));
remove subdocument
const removeAuthor = async (courseId,authorId){
const course = await Course.findById(courseId);
const author = course.authors.id(authorId);
author.deleteOne();
course.save();
}
removeAuthor("6234125asdf25c554","2348794j78678sd78");
remove subdocument directly in database
const removeAuthor = async (courseId){
const course = await Course.update(_id:courseId,{
$unset:{'author':''}
});
}
removeAuthor("6234125asdf25c554");
update subdocument
const updateAuthor = async (courseId,newName){
const course = await Course.findById(courseId);
course.author.name = newName;
course.save();
}
updateAuthor("6234125asdf25c554","James McGill");
update subdocument directly in database
const updateAuthor = async (courseId,newName){
const course = await Course.update(_id:courseId,{
$set:{'author.name':newName}
});
}
updateAuthor("6234125asdf25c554","James McGill");