Два типи об’єктів здаються настільки близькими один до одного, що наявність обох відчуває себе зайвим. Який сенс мати і схеми, і моделі?
Два типи об’єктів здаються настільки близькими один до одного, що наявність обох відчуває себе зайвим. Який сенс мати і схеми, і моделі?
Відповіді:
Часто найпростіший спосіб відповісти на запитання цього типу - на прикладі. У цьому випадку хтось це вже зробив за мене :)
Погляньте тут:
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
РЕДАГУВАТИ: Оригінальний допис (як згадувалося в коментарях), здається, більше не існує, тому я відтворюю його нижче. Якщо воно коли-небудь повернеться або якщо воно щойно переїхало, повідомте мене про це.
Він дає пристойний опис використання схем у моделях у мангусті та чому ви хочете це зробити, а також показує, як проштовхувати завдання через модель, тоді як схема стосується структури тощо.
Оригінальне повідомлення:
Почнемо з простого прикладу вбудовування схеми всередину моделі.
var TaskSchema = new Schema({
name: String,
priority: Number
});
TaskSchema.virtual('nameandpriority')
.get( function () {
return this.name + '(' + this.priority + ')';
});
TaskSchema.method('isHighPriority', function() {
if(this.priority === 1) {
return true;
} else {
return false;
}
});
var ListSchema = new Schema({
name: String,
tasks: [TaskSchema]
});
mongoose.model('List', ListSchema);
var List = mongoose.model('List');
var sampleList = new List({name:'Sample List'});
Я створив новий TaskSchema
об’єкт із базовою інформацією, яку може мати завдання. Віртуальний атрибут Mongoose налаштований для зручного поєднання імені та пріоритету Завдання. Тут я вказав лише геттер, але також підтримуються віртуальні сетери.
Я також визначив простий метод завдання, покликаний isHighPriority
продемонструвати, як методи працюють із цим налаштуванням.
У ListSchema
визначенні ви помітите, як ключ завдань налаштований на вміщення масиву TaskSchema
об’єктів. Ключ завдання стане екземпляром, DocumentArray
який надає спеціальні методи роботи з вбудованими документами Монго.
Наразі я лише передав ListSchema
об'єкт у mongoose.model і залишив TaskSchema поза. Технічно не потрібно перетворювати TaskSchema
на офіційну модель, оскільки ми не будемо зберігати її у власній колекції. Пізніше я покажу вам, як це нічого не шкодить, і це може допомогти впорядкувати всі ваші моделі однаково, особливо коли вони починають охоплювати кілька файлів.
За допомогою List
налаштування моделі додамо до неї пару завдань і збережемо їх у Монго.
var List = mongoose.model('List');
var sampleList = new List({name:'Sample List'});
sampleList.tasks.push(
{name:'task one', priority:1},
{name:'task two', priority:5}
);
sampleList.save(function(err) {
if (err) {
console.log('error adding new list');
console.log(err);
} else {
console.log('new list successfully saved');
}
});
Атрибут задач на екземплярі нашої List
моделі ( simpleList
) працює як звичайний масив JavaScript, і ми можемо додавати до нього нові завдання за допомогою push. Важливо помітити, що завдання додаються як звичайні об'єкти JavaScript. Це тонка відмінність, яка може бути не одразу інтуїтивною.
Ви можете перевірити за допомогою оболонки Mongo, що новий список та завдання були збережені в mongo.
db.lists.find()
{ "tasks" : [
{
"_id" : ObjectId("4dd1cbeed77909f507000002"),
"priority" : 1,
"name" : "task one"
},
{
"_id" : ObjectId("4dd1cbeed77909f507000003"),
"priority" : 5,
"name" : "task two"
}
], "_id" : ObjectId("4dd1cbeed77909f507000001"), "name" : "Sample List" }
Тепер ми можемо використати ObjectId
для підтягування Sample List
та повторення своїх завдань.
List.findById('4dd1cbeed77909f507000001', function(err, list) {
console.log(list.name + ' retrieved');
list.tasks.forEach(function(task, index, array) {
console.log(task.name);
console.log(task.nameandpriority);
console.log(task.isHighPriority());
});
});
Якщо ви запустите цей останній біт коду, ви отримаєте повідомлення про помилку, що вбудований документ не має методу isHighPriority
. У поточній версії Mongoose ви не можете безпосередньо отримати доступ до методів у вбудованих схемах. Існує відкритий квиток, щоб виправити це, і після того, як поставив запитання до групи Google Mongoose, manimal45 опублікував корисну практичну роботу, яку слід використовувати зараз.
List.findById('4dd1cbeed77909f507000001', function(err, list) {
console.log(list.name + ' retrieved');
list.tasks.forEach(function(task, index, array) {
console.log(task.name);
console.log(task.nameandpriority);
console.log(task._schema.methods.isHighPriority.apply(task));
});
});
Якщо ви запустите цей код, ви побачите наступний результат у командному рядку.
Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false
Маючи на увазі це навколо, давайте перетворимо модель TaskSchema
на мангуста.
mongoose.model('Task', TaskSchema);
var Task = mongoose.model('Task');
var ListSchema = new Schema({
name: String,
tasks: [Task.schema]
});
mongoose.model('List', ListSchema);
var List = mongoose.model('List');
TaskSchema
Визначення таке ж , як і раніше , так що я залишив його. Після того, як він перетворився на модель, ми все ще можемо отримати доступ до основного об’єкта Schema, використовуючи крапкові позначення.
Давайте створимо новий список і вбудуємо в нього два екземпляри моделі Завдання.
var demoList = new List({name:'Demo List'});
var taskThree = new Task({name:'task three', priority:10});
var taskFour = new Task({name:'task four', priority:11});
demoList.tasks.push(taskThree.toObject(), taskFour.toObject());
demoList.save(function(err) {
if (err) {
console.log('error adding new list');
console.log(err);
} else {
console.log('new list successfully saved');
}
});
Поки ми вбудовуємо екземпляри моделі Завдання у Список, ми закликаємо toObject
їх перетворити свої дані у звичайні об’єкти JavaScript, які List.tasks
DocumentArray
очікується. Коли ви зберігаєте екземпляри моделі таким чином, ваші вбудовані документи будуть містити ObjectIds
.
Повний приклад коду доступний як суть . Сподіваємось, ці методи роботи допоможуть згладити ситуацію, оскільки Mongoose продовжує розвиватися. Я все ще досить новачок у Mongoose та MongoDB, тому, будь ласка, не соромтеся ділитися кращими рішеннями та порадами в коментарях. Щасливого моделювання даних!
Схема - це об’єкт, який визначає структуру будь-яких документів, які будуть зберігатися у вашій колекції MongoDB; це дозволяє визначити типи та валідатори для всіх ваших елементів даних.
Модель - це об’єкт, який забезпечує легкий доступ до іменованої колекції, що дозволяє запитувати колекцію та використовувати схему для перевірки будь-яких документів, збережених у цій колекції. Він створюється поєднанням схеми, з'єднання та назви колекції.
Спочатку сформульований Валері Карповим, Блог MongoDB
Я не думаю, що прийнята відповідь насправді відповідає на поставлене питання. Відповідь не пояснює, чому Mongoose вирішив вимагати від розробника надати як схему, так і змінну Model. Приклад фреймворку, коли вони ліквідували потребу розробникадля визначення схеми даних використовується django - розробник записує їх моделі у файл models.py і залишає за структурою для управління схемою. Перша причина, яка спадає на думку, чому вони це роблять, враховуючи мій досвід роботи з django, - це простота використання. Можливо, що важливіше, це принцип СУХОГО (не повторюйся) - вам не потрібно пам’ятати про оновлення схеми при зміні моделі - django зробить це за вас! Rails також керує схемою даних для вас - розробник не редагує схему безпосередньо, а змінює її, визначаючи міграції, які маніпулюють схемою.
Однією з причин, через яку я міг зрозуміти, що Mongoose відокремлює схему, а модель є випадки, коли ви хочете побудувати модель із двох схем. Такий сценарій може внести більше складності, ніж варто керувати - якщо у вас є дві схеми, якими керує одна модель, чому це не одна схема?
Можливо, оригінальне питання - це більше пережиток традиційної системи реляційних баз даних. У світовому світі NoSQL / Монго, можливо, схема є трохи гнучкішою, ніж MySQL / PostgreSQL, і, отже, зміна схеми є більш поширеною практикою.
Щоб зрозуміти чому? ви повинні зрозуміти, що насправді є Мангуст?
Ну, мангуст - це бібліотека моделювання даних об’єктів для MongoDB та Node JS, що забезпечує більш високий рівень абстракції. Отже, це трохи схоже на взаємозв'язок між Express і Node, тому Express є шаром абстракції над звичайним Node, тоді як Mongoose - шаром абстракції над звичайним драйвером MongoDB.
Бібліотека моделювання даних об’єктів - це лише спосіб для нас написати код Javascript, який потім буде взаємодіяти з базою даних. Тож ми могли б просто скористатися звичайним драйвером MongoDB для доступу до нашої бази даних, він би працював чудово.
Але замість цього ми використовуємо Mongoose, оскільки він надає нам набагато більше функціональних можливостей, що дозволяє швидше та простіше розробляти наші програми.
Отже, деякі функції Mongoose надають нам схеми для моделювання наших даних та взаємозв’язків, просту перевірку даних, простий API запитів, проміжне програмне забезпечення та багато іншого.
У Mongoose схема є місцем, де ми моделюємо наші дані, де описуємо структуру даних, значення за замовчуванням і перевірку, потім беремо цю схему і створюємо з неї модель, модель в основному є обгорткою навколо схеми, що дозволяє нам фактично взаємодіяти з базою даних для створення, видалення, оновлення та читання документів.
Створимо модель зі схеми.
const tourSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'A tour must have a name'],
unique: true,
},
rating: {
type: Number,
default: 4.5,
},
price: {
type: Number,
required: [true, 'A tour must have a price'],
},
});
//tour model
const Tour = mongoose.model('Tour', tourSchema);
Відповідно до конвекції перша буква назви моделі повинна бути написана великими літерами.
Давайте створимо екземпляр нашої моделі, яку ми створили за допомогою мангуста та схеми. також взаємодіяти з нашою базою даних.
const testTour = new Tour({ // instance of our model
name: 'The Forest Hiker',
rating: 4.7,
price: 497,
});
// saving testTour document into database
testTour
.save()
.then((doc) => {
console.log(doc);
})
.catch((err) => {
console.log(err);
});
Отже, наявність і схами, і мангуста-мангуста полегшує наше життя.