Два типа объектов кажутся настолько близкими друг к другу, что оба они кажутся излишними. Какой смысл иметь как схемы, так и модели?
Почему у Mongoose есть как схемы, так и модели?
Ответ 1
Часто самый простой способ ответить на этот вопрос - это пример. В этом случае кто-то уже сделал это для меня:)
Взгляните сюда:
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 предназначен для удобного объединения имени и приоритета задачи. Я указал только на getter, но поддерживаются виртуальные сеттеры.
Я также определил простой метод задачи, называемый isHighPriority
, чтобы продемонстрировать, как методы работают с этой установкой.
В определении ListSchema
вы увидите, как ключ задач сконфигурирован для хранения массива объектов TaskSchema
. Ключ задачи станет экземпляром DocumentArray
, который предоставляет специальные методы для обработки встроенных документов Mongo.
Пока я только передал объект ListSchema
в mongoose.model и вышел из TaskSchema. Технически нет необходимости превращать TaskSchema
в формальную модель, поскольку мы не будем ее сохранять в своей собственной коллекции. Позже Ill покажет вам, как это ничего не наносит вреда, если вы это сделаете, и это может помочь организовать все ваши модели таким же образом, особенно когда они начинают охватывать несколько файлов.
С помощью установки List
можно добавить несколько задач к ней и сохранить их в Mongo.
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');
}
});
Атрибут tasks в экземпляре нашей модели 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 вы не можете использовать методы доступа на встроенных схемах напрямую. Theres открыть билет, чтобы исправить его, и после того, как он задал вопрос группе 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.
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 продолжает развиваться. Im все еще довольно новый для Mongoose и MongoDB, поэтому, пожалуйста, не стесняйтесь делиться лучшими решениями и советами в комментариях. Счастливое моделирование данных!
Ответ 2
Схема - это объект, который определяет структуру любых документов, которые будут храниться в вашей коллекции MongoDB; он позволяет вам определять типы и валидаторы для всех ваших элементов данных.
Модель - это объект, который дает вам легкий доступ к именованной коллекции, позволяя вам запрашивать коллекцию и использовать схему для проверки любых документов, которые вы сохраняете в этой коллекции. Он создается путем объединения имени схемы, соединения и коллекции.
Первоначально сформулированный Валерием Карповым, Блог MongoDB
Ответ 3
Я не думаю, что принятый ответ действительно отвечает на поставленный вопрос. Ответ не объясняет, почему Mongoose решил потребовать от разработчика предоставить как схему, так и переменную модели. Примером структуры, в которой они устраняют необходимость разработки разработчиком схемы данных, является django - разработчик записывает свои модели в файл models.py и оставляет его в структуре для управления схемой. Первая причина, которая приходит на ум за то, почему они это делают, учитывая мой опыт работы с django, - это простота использования. Возможно, что более важно - принцип DRY (не повторяйте сам) - вам не нужно запоминать обновленную схему при смене модели - django сделает это за вас! Rails также управляет схемой данных для вас - разработчик напрямую не редактирует схему, а изменяет ее, определяя миграции, которые управляют схемой.
Одна из причин, по которой я мог понять, что Mongoose отделяет схему, а модель - это экземпляры, где вы хотели бы построить модель из двух схем. Такой сценарий может привести к большей сложности, чем того стоит - если у вас есть две схемы, управляемые одной моделью, почему они не являются одной схемой?
Возможно, исходный вопрос - скорее реликвия традиционной системы реляционных баз данных. В мире NoSQL/Mongo, возможно, схема немного более гибкая, чем MySQL/PostgreSQL, и, таким образом, изменение схемы является более распространенной практикой.