Моделиране на взаимоотношения

Основното предизвикателство при моделирането на данни е балансирането на нуждите на приложението, характеристиките на производителността на двигателя на базата данни и моделите за извличане на данни. Когато проектирате модели на данни, винаги вземайте предвид използването на данните от приложението (т.е. заявки, актуализации и обработка на данните), както и присъщата структура на самите данни.

Ключовото решение при проектирането на модели на данни за MongoDB приложения се върти около структурата на документите и как приложението представя връзките между данните. MongoDB позволява свързани данни да бъдат вградени в един документ.

Референтен документ

Препратките съхраняват връзките между данните, като включват връзки или препратки от един документ към друг. Приложенията могат да разрешат тези „препратки“ за достъп до свързаните данни. В общи линии това са нормализирани модели на данни.

//MODEL AUTHOR
const Author = mongoose.model('Author', new mongoose.Schema({
name: String,
bio: String,
website: String
}));

//MODEL COURSE was relationalship with Author model

const Course = mongoose.model('Course', new mongoose.Schema({
name: String,
authorId:{
type: mongoose.Schema.Types.ObjectId,
ref:'Author'
}
}));

Създаване на авторски модел

async function createAuthor(name, bio, website) {
     const author = new Author({name, bio, website });
     const result = await author.save();
console.log(result);
}
createAuthor('Ika', 'My bio', 'My Website');

Създайте модел на курса

async function createCourse(name, authorId) {
   const course = new Course({name, authorId});
   const result = await course.save();
console.log(result);
}
createCourse('Node Course', '622b551b1b348da807f723c0')//(nameCourse , authorId)

списък курс

async function listCourses() {
const courses = await Course
.find()
.populate('authorId')// find all populate in author model
.select('name');
console.log(courses);
}
listCourses();

.populate() използвайте за показване на цялата популация в релационна таблица. Там ще се покаже цялото съдържание на автора на таблицата по релационен authorId.

Вграждане на документи

За да моделираме връзки между свързани данни, можем или да препратим към документ, или да го вградим в друг документ. При препратка към документ наистина няма връзка между тези два документа. Така че е възможно да се направи препратка към несъществуващ документ. Реферирането на документи (нормализиране) е добър подход, когато искате да наложите последователност на данните. Тъй като ще има единичен екземпляр на обект в базата данни. Но този подход има отрицателно въздействие върху производителността на вашите заявки, защото в MongoDB не можем да ПРИСЪЕДИНЯВАМЕ документи, както правим в релационни бази данни. Така че, за да получим пълно представяне на документ със свързаните с него документи, трябва да изпратим множество заявки към базата данни. Вграждането на документи (денормализиране) решава този проблем. Можем да прочетем пълно представяне на документ с една заявка. Всички необходими данни са вградени в един документ и неговите деца. Но това също означава, че ще имаме множество копия на данни на различни места. Докато съхранението не е проблем в наши дни, наличието на множество копия означава, че промените, направени в оригиналния документ, може да не се разпространят във всички копия. Ако сървърът на базата данни умре по време на актуализация, някои документи ще бъдат непоследователни. За всеки бизнес, за всеки проблем трябва да зададете следния въпрос: „можем ли да толерираме данните да бъдат непоследователни за кратък период от време?“ Ако не, ще трябва да използвате препратки. Но отново, това означава, че вашите заявки ще бъдат по-бавни.

Позоваване на документ

async function listCourses() {
const courseSchema = new mongoose.Schema({ author: { type: mongoose.Schema.Types.ObjectId, ref: ‘Author’ } })

Позоваване на документ

const courseSchema = new mongoose.Schema({ 
author: {   
       type: new mongoose.Schema({             
       name: String,              
       bio: String         
      })   
    } 
}) 
const Course =

Вградените документи нямат метод за запазване. Те могат да бъдат запазени само в контекста на техния родител.

Актуализиране на вграден документ

const course = await Course.findById(courseId);
course.author.name = ‘New Name’; 
course.save();

целия код на embedding.js

const mongoose = require('mongoose');
//CONNECTION DATABASE
mongoose.connect('mongodb://localhost/playground')
.then(() => console.log('Connected to MongoDB...'))
.catch(err => console.error('Could not connect to MongoDB...', err));
//MODEL AUTHOR
const authorSchema = new mongoose.Schema({
       name: String,
       bio: String,
       website: String  });
const Author = mongoose.model('Author', authorSchema);
//MODEL COURSE
const Course = mongoose.model('Course', new mongoose.Schema({
         name: String,
         authors:[authorSchema]}));
                            //CRUD
//CREATE COURSE
async function createCourse(name, authors) {
const course = new Course({ name, authors });
const result = await course.save();
console.log(result);
}
//READ COURSES
async function listCourses() {
const courses = await Course.find();
console.log(courses);
}
//UPDATE COURSE
async function update(courseId) {
const course = await Course.findById(courseId);
course.author.name="Ika sari apriliyani";
course.save()
console.log(course);
}
async function addAuthor(courseId,author) {
const course=await Course.findById(courseId);
course.authors.push(author)
course.save()
}
//DELETE COURSE
async function removeAuthor(courseId,authorId) {
const course=await Course.findById(courseId);
const author = await course.authors.id(authorId)
author.remove()
course.save()
}
//createCourse(name, authors)
//listCourses()
// update('622cc20af81c5e7c38e80a3a')
// createCourse('Node Course', [new Author({ name: 'Ika' })]);
// addAuthor('622ccaa98004b2252cee4310', new Author({ name: 'Amy' }));
// removeAuthor('622ccaa98004b2252cee4310','622ccb54ec686c07c6038c18')

Транзакции

Нямаме транзакции в MongoDB. За да реализираме транзакции, ние използваме модел, наречен „Two Phase Commit“. Ако не искате ръчно да внедрите този модел, използвайте пакета Fawn NPM:

Изпълнение на транзакции с помощта на Fawn

 try {    
         await new Fawn.Task()        
         .save(‘rentals’, newRental)       
         .update(‘movies’, { _id: movie._id }, 
{ $inc:numberInStock: -1 }})                                              .run(); } 
catch (ex) {     // At this point, all operations are automatically rolled back}

ИД на обект

ObjectID са почти уникални. На теория има шанс два ObjectID да бъдат равни, но шансовете са много ниски (1/16 000 000) за повечето приложения в реалния свят.

ObjectID се генерират от драйвера MongoDB и се използват за уникално идентифициране на документ. Те се състоят от 12 байта:

  • 4 байта: клеймо за време
  • 3 байта: идентификатор на машината
  • 2 байта: идентификатор на процеса
  • 3 чао: брояч

Валидиране на ObjectIDs

mongoose.Types.ObjectID.isValid(id);

За да потвърдите ObjectID с помощта на joi, използвайте пакета joi-objectid NPM.

Основна препоръка от курс Node JS Код с Mosh