为什么Mongoose既有模式又有模型?

两种物体似乎彼此如此接近,以致两者都感觉多余。 同时拥有模式和模型有什么意义?

通常最简单的方法来回答这种types的问题是一个例子。 在这种情况下,有人已经为我做了:)

看看这里:

http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/

编辑:原来的职位(如在评论中提到)似乎不再存在,所以我在下面重现。 如果它返回,或者它刚刚移动,请让我知道。

它给出了在mongoose模型中使用模式的一个体面的描述,以及为什么你想要这样做,并且还展示了如何通过模型推送任务,而模式是关于结构等的。

原帖:

我们从一个简单的模型embedded模式的例子开始。

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'}); 

我用任务可能具有的基本信息创build了一个新的TaskSchema对象。 设置Mongoose 虚拟属性可方便地将Task的名称和优先级结合起来。 我只在这里指定了一个getter,但是也支持虚拟设置器。

我还定义了一个名为isHighPriority的简单任务方法来演示如何使用此设置方法。

ListSchema定义中,您将注意到如何将任务键configuration为包含TaskSchema对象的数组。 任务键将成为DocumentArray一个实例,它提供了处理embedded式Mongo文档的特殊方法。

现在我只将ListSchema对象传入ListSchema ,并将TaskSchema留下。 从技术上说,没有必要把TaskSchema转换成一个正式的模型,因为我们不会将它保存在自己的集合中。 稍后,我将向您展示如何执行这些操作,并且可以帮助您以相同的方式组织所有模型,尤其是当它们跨越多个文件时。

通过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'); } }); 

我们的List模型( simpleList )的实例上的tasks属性就像一个普通的JavaScript数组,我们可以使用push向它添加新的任务。 重要的是要注意的是,任务被添加为普通的JavaScript对象。 这是一个微妙的区别,可能不是直接的。

你可以从Mongo shellvalidation新的列表和任务已经保存到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()); }); }); 

如果你运行最后一段代码,你会得到一个错误,说明embedded式文件没有isHighPriority方法。 在当前版本的Mongoose中,您无法直接访问embedded式架构上的方法。 有一张可以解决的问题,在向Mongoose Google Group提出问题之后,manimal45发布了一个有用的解决scheme,以供现在使用。

 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对象。

我们创build一个新的列表,并在其中embedded两个任务模型实例。

 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'); } }); 

当我们将Task模型实例embeddedList中时,我们调用toObject来将它们的数据转换为List.tasks DocumentArray期望的普通JavaScript对象。 以这种方式保存模型实例时,embedded式文档将包含ObjectIds

完整的代码示例可作为要点 。 希望随着mongoose的不断发展,这些解决scheme可以帮助你顺利完成任务。 对于Mongoose和MongoDB,我还是很新的,所以请随时在评论中分享更好的解决scheme和技巧。 快乐的数据build模!

模式是定义将存储在MongoDB集合中的任何文档的结构的对象; 它使您能够定义所有数据项的types和validation器。

模型是一个对象,使您可以轻松访问指定的集合,允许您查询集合并使用该模式来validation您保存到该集合的任何文档。 它是通过结合模式,连接和集合名称创build的。

最初由MongoDB Blog的 Valeri Karpov 说过

我不认为接受的答案实际上回答了提出的问题。 答案并不能解释为什么 Mongoose决定要求开发者提供Schema和Modelvariables。 开发人员不需要定义数据模式的框架的一个例子是django – 开发人员将他们的模型写入models.py文件,并将其留在框架中以pipe理模式。 考虑到我使用django的经验,为什么要这么做,首先想到的是易用性。 也许更重要的是DRY(不要重复你自己)原则 – 当你改变模型时,你不必记得更新模式 – django会为你做的! Rails还为您pipe理数据模式 – 开发人员不直接编辑模式,而是通过定义操作模式的迁移来更改模式。

我能理解的一个原因是Mongoose会将模式和模型分开,这是您希望从两个模式构build模型的实例。 这样的情况可能会带来更多的复杂性,而不是值得pipe理的 – 如果你有两个由一个模型pipe理的模式,他们为什么不是一个模式呢?

也许原来的问题更多的是传统的关系数据库系统的遗迹。 在世界NoSQL / Mongo世界中,模式可能比MySQL / PostgreSQL更灵活,因此更改模式更为常见。