Чому Mongoose має як схеми, так і моделі?


92

Два типи об’єктів здаються настільки близькими один до одного, що наявність обох відчуває себе зайвим. Який сенс мати і схеми, і моделі?

Відповіді:


61

Часто найпростіший спосіб відповісти на запитання цього типу - на прикладі. У цьому випадку хтось це вже зробив за мене :)

Погляньте тут:

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, тому, будь ласка, не соромтеся ділитися кращими рішеннями та порадами в коментарях. Щасливого моделювання даних!


3
Зазвичай рекомендується не подавати голого посилання як відповідь на запитання, розміщені в SO, оскільки посилання може перестати працювати (як у цьому випадку). Принаймні скопіюйте / пропустіть і цитуйте відповідні розділи статей, на які ви посилаєтесь.
Behrang Saeedzadeh

1
зроблено - це все ще було в кеш-пам’яті Google, настільки відносно просто
Адам Комерфорд,

1
Для запису було виправлено проблему із вбудованим документом: github.com/LearnBoost/mongoose/issues/249#ref-commit-e18077a
Дакота

5
Я не намагаюся зливати на чийсь парад, але ця відповідь частіше нагадує підручник: відповідь як, але не чому. Незважаючи на те , менше на голоси, я знайшов таку відповідь набагато більш корисним: stackoverflow.com/a/22950402/26331
aaaidan

2
Я бачив цю відповідь (і підтримав її), на неї відповіли та прийняли її за 2 роки до цього. Я щасливий, що можна знайти кращу відповідь, ні на кого параду не йде дощ, і з лютого 2015 року є посилання на відповідь, на яку ви посилаєтесь у коментарях до запитання, тому я не відчував потреби самостійно пов’язувати це
Адам Комерфорд,

54

Схема - це об’єкт, який визначає структуру будь-яких документів, які будуть зберігатися у вашій колекції MongoDB; це дозволяє визначити типи та валідатори для всіх ваших елементів даних.

Модель - це об’єкт, який забезпечує легкий доступ до іменованої колекції, що дозволяє запитувати колекцію та використовувати схему для перевірки будь-яких документів, збережених у цій колекції. Він створюється поєднанням схеми, з'єднання та назви колекції.

Спочатку сформульований Валері Карповим, Блог MongoDB


5

Я не думаю, що прийнята відповідь насправді відповідає на поставлене питання. Відповідь не пояснює, чому Mongoose вирішив вимагати від розробника надати як схему, так і змінну Model. Приклад фреймворку, коли вони ліквідували потребу розробникадля визначення схеми даних використовується django - розробник записує їх моделі у файл models.py і залишає за структурою для управління схемою. Перша причина, яка спадає на думку, чому вони це роблять, враховуючи мій досвід роботи з django, - це простота використання. Можливо, що важливіше, це принцип СУХОГО (не повторюйся) - вам не потрібно пам’ятати про оновлення схеми при зміні моделі - django зробить це за вас! Rails також керує схемою даних для вас - розробник не редагує схему безпосередньо, а змінює її, визначаючи міграції, які маніпулюють схемою.

Однією з причин, через яку я міг зрозуміти, що Mongoose відокремлює схему, а модель є випадки, коли ви хочете побудувати модель із двох схем. Такий сценарій може внести більше складності, ніж варто керувати - якщо у вас є дві схеми, якими керує одна модель, чому це не одна схема?

Можливо, оригінальне питання - це більше пережиток традиційної системи реляційних баз даних. У світовому світі NoSQL / Монго, можливо, схема є трохи гнучкішою, ніж MySQL / PostgreSQL, і, отже, зміна схеми є більш поширеною практикою.


Як ніби схеми проти моделі недостатньо Повторюючи себе, ви стикаєтеся з більшою кількістю дублювань при спробі підтримати відповідний інтерфейс TypeScript і навіть більше при створенні схеми GraphQL.
Дан Даскалеску,

0

Щоб зрозуміти чому? ви повинні зрозуміти, що насправді є Мангуст?

Ну, мангуст - це бібліотека моделювання даних об’єктів для 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);
  });

Отже, наявність і схами, і мангуста-мангуста полегшує наше життя.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.