mongodb 为什么 Mongoose 既有模式又有模型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9127174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does Mongoose have both schemas and models?
提问by Randomblue
The two types of objects seem to be so close to one another that having both feels redundant. What is the point of having bothschemas and models?
这两种类型的物体似乎彼此如此接近,以至于同时拥有两者都感觉多余。什么是具有点既架构和模式?
采纳答案by Adam Comerford
Often the easiest way to answer this type of question is with an example. In this case, someone has already done it for me :)
通常,回答此类问题的最简单方法是举例。在这种情况下,有人已经为我完成了:)
Take a look here:
看看这里:
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
http://rawberg.com/blog/nodejs/mongoose-orm-nested-models/
EDIT:The original post (as mentioned in the comments) seems to no longer exist, so I am reproducing it below. Should it ever return, or if it has just moved, please let me know.
编辑:原始帖子(如评论中所述)似乎不再存在,所以我在下面复制它。如果它返回,或者它刚刚移动,请告诉我。
It gives a decent description of using schemas within models in mongoose and why you would want to do it, and also shows you how to push tasks via the model while the schema is all about the structure etc.
它给出了在 mongoose 模型中使用模式的体面描述以及你为什么想要这样做,还向你展示了如何通过模型推送任务,而模式全都与结构等有关。
Original Post:
原帖:
Let's start with a simple example of embedding a schema inside a model.
让我们从在模型中嵌入模式的简单示例开始。
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'});
I created a new TaskSchema
object with basic info a task might have. A Mongoose virtual attributeis setup to conveniently combine the name and priority of the Task. I only specified a getter here but virtual setters are supported as well.
我创建了一个新TaskSchema
对象,其中包含任务可能具有的基本信息。设置了Mongoose虚拟属性以方便地组合任务的名称和优先级。我在这里只指定了一个 getter,但也支持虚拟 setter。
I also defined a simple task method called isHighPriority
to demonstrate how methods work with this setup.
我还定义了一个简单的任务方法,isHighPriority
用于演示方法如何与此设置一起工作。
In the ListSchema
definition you'll notice how the tasks key is configured to hold an array of TaskSchema
objects. The task key will become an instance of DocumentArray
which provides special methods for dealing with embedded Mongo documents.
在ListSchema
定义中,您会注意到 tasks 键是如何配置为保存TaskSchema
对象数组的。任务键将成为一个实例,DocumentArray
它提供了处理嵌入式 Mongo 文档的特殊方法。
For now I only passed the ListSchema
object into mongoose.model and left the TaskSchema out. Technically it's not necessary to turn the TaskSchema
into a formal model since we won't be saving it in it's own collection. Later on I'll show you how it doesn't harm anything if you do and it can help to organize all your models in the same way especially when they start spanning multiple files.
现在我只将ListSchema
对象传递到 mongoose.model 并忽略了 TaskSchema。从技术上讲,没有必要将其TaskSchema
转换为正式模型,因为我们不会将其保存在自己的集合中。稍后我将向您展示如果您这样做不会损害任何东西,并且它可以帮助以相同的方式组织所有模型,尤其是当它们开始跨越多个文件时。
With the List
model setup let's add a couple tasks to it and save them to Mongo.
通过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');
}
});
The tasks attribute on the instance of our List
model (simpleList
) works like a regular JavaScript array and we can add new tasks to it using push. The important thing to notice is the tasks are added as regular JavaScript objects. It's a subtle distinction that may not be immediately intuitive.
我们List
模型 ( simpleList
)实例上的 tasks 属性就像一个常规的 JavaScript 数组,我们可以使用 push 向它添加新任务。需要注意的重要一点是任务是作为常规 JavaScript 对象添加的。这是一个微妙的区别,可能不会立即直观。
You can verify from the Mongo shell that the new list and tasks were saved to mongo.
您可以从 Mongo shell 验证新列表和任务是否已保存到 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" }
Now we can use the ObjectId
to pull up the Sample List
and iterate through its tasks.
现在我们可以使用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());
});
});
If you run that last bit of code you'll get an error saying the embedded document doesn't have a method isHighPriority
. In the current version of Mongoose you can't access methods on embedded schemas directly. There's an open ticketto fix it and after posing the question to the Mongoose Google Group, manimal45 posted a helpful work-around to use for now.
如果您运行最后一点代码,您将收到一条错误消息,指出嵌入的文档没有方法isHighPriority
。在当前版本的 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));
});
});
If you run that code you should see the following output on the command line.
如果您运行该代码,您应该会在命令行上看到以下输出。
Sample List retrieved
task one
task one (1)
true
task two
task two (5)
false
With that work-around in mind let's turn the TaskSchema
into a Mongoose model.
考虑到这种变通方法,让我们将其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');
The TaskSchema
definition is the same as before so I left it out. Once its turned into a model we can still access it's underlying Schema object using dot notation.
该TaskSchema
定义是一样的,所以我离开它之前。一旦它变成一个模型,我们仍然可以使用点表示法访问它的底层 Schema 对象。
Let's create a new list and embed two Task model instances within it.
让我们创建一个新列表并在其中嵌入两个 Task 模型实例。
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');
}
});
As we're embedding the Task model instances into the List we're calling toObject
on them to convert their data into plain JavaScript objects that the List.tasks
DocumentArray
is expecting. When you save model instances this way your embedded documents will contain ObjectIds
.
当我们将 Task 模型实例嵌入到 List 中时,我们调用toObject
它们将它们的数据转换List.tasks
DocumentArray
为期望的纯 JavaScript 对象。当您以这种方式保存模型实例时,您的嵌入文档将包含ObjectIds
.
The complete code example is available as a gist. Hopefully these work-arounds help smooth things over as Mongoose continues to develop. I'm still pretty new to Mongoose and MongoDB so please feel free to share better solutions and tips in the comments. Happy data modeling!
完整的代码示例可作为 gist 使用。希望随着 Mongoose 的不断发展,这些变通办法可以帮助解决问题。我对 Mongoose 和 MongoDB 还是很陌生,所以请随时在评论中分享更好的解决方案和技巧。快乐的数据建模!
回答by Zeeshan Hassan Memon
Schemais an object that defines the structure of any documents that will be stored in your MongoDB collection; it enables you to define types and validators for all of your data items.
Schema是一个对象,它定义了将存储在 MongoDB 集合中的任何文档的结构;它使您能够为所有数据项定义类型和验证器。
Modelis an object that gives you easy access to a named collection, allowing you to query the collection and use the Schema to validate any documents you save to that collection. It is created by combining a Schema, a Connection, and a collection name.
模型是一个对象,可让您轻松访问命名集合,允许您查询集合并使用架构来验证您保存到该集合的任何文档。它是通过组合架构、连接和集合名称来创建的。
Originally phrased by Valeri Karpov, MongoDB Blog
最初由MongoDB 博客的Valeri Karpov 提出
回答by johnklawlor
I don't think the accepted answer actually answers the question that was posed. The answer doesn't explain whyMongoose has decided to require a developer to provide both a Schema and a Model variable. An example of a framework where they have eliminated the need for the developerto define the data schema is django--a developer writes up their models in the models.py file, and leaves it to the framework to manage the schema. The first reason that comes to mind for why they do this, given my experience with django, is ease-of-use. Perhaps more importantly is the DRY (don't repeat yourself) principle--you don't have to remember to update the schema when you change the model--django will do it for you! Rails also manages the schema of the data for you--a developer doesn't edit the schema directly, but changes it by defining migrations that manipulate the schema.
我认为接受的答案实际上并没有回答提出的问题。答案并没有解释为什么Mongoose 决定要求开发人员同时提供 Schema 和 Model 变量。一个不需要开发人员的框架示例定义数据模式是 django——开发人员在 models.py 文件中编写他们的模型,并将其留给框架来管理模式。考虑到我使用 Django 的经验,他们这样做的第一个原因是易于使用。也许更重要的是 DRY(不要重复自己)原则——你不必记住在更改模型时更新架构——django 会为你做的!Rails 还为您管理数据的模式——开发人员不直接编辑模式,而是通过定义操作模式的迁移来更改模式。
One reason I could understand that Mongoose would separate the schema and the model is instances where you would want to build a model from two schemas. Such a scenario might introduce more complexity than is worth managing--if you have two schemas that are managed by one model, why aren't they one schema?
我能理解 Mongoose 将模式和模型分开的原因之一是您希望从两个模式构建模型的实例。这样的场景可能会引入比值得管理更多的复杂性——如果您有两个模式由一个模型管理,为什么它们不是一个模式?
Perhaps the original question is more a relic of the traditional relational database system. In world NoSQL/Mongo world, perhaps the schema is a little more flexible than MySQL/PostgreSQL, and thus changing the schema is more common practice.
也许最初的问题更像是传统关系数据库系统的遗物。在世界 NoSQL/Mongo 世界中,也许模式比 MySQL/PostgreSQL 更灵活,因此更改模式是更常见的做法。
回答by Lord
To understand why? you have to understand what actually is Mongoose?
要明白为什么?你必须了解猫鼬究竟是什么?
Well, the mongoose is an object data modeling library for MongoDB and Node JS, providing a higher level of abstraction. So it's a bit like the relationship between Express and Node, so Express is a layer of abstraction over regular Node, while Mongoose is a layer of abstraction over the regular MongoDB driver.
嗯,mongoose 是 MongoDB 和 Node JS 的对象数据建模库,提供了更高级别的抽象。所以有点像Express和Node的关系,所以Express是对普通Node的抽象层,而Mongoose是对普通MongoDB驱动的抽象层。
An object data modeling library is just a way for us to write Javascript code that will then interact with a database. So we could just use a regular MongoDB driver to access our database, it would work just fine.
对象数据建模库只是我们编写与数据库交互的 Javascript 代码的一种方式。所以我们可以只使用一个普通的 MongoDB 驱动程序来访问我们的数据库,它会工作得很好。
But instead we use Mongoose because it gives us a lot more functionality out of the box, allowing for faster and simpler development of our applications.
但我们使用 Mongoose 是因为它为我们提供了更多开箱即用的功能,允许更快、更简单地开发我们的应用程序。
So, some of the features Mongoose gives us schemas to model our data and relationship, easy data validation, a simple query API, middleware, and much more.
因此,Mongoose 的一些功能为我们提供了模式来建模我们的数据和关系、轻松的数据验证、简单的查询 API、中间件等等。
In Mongoose, a schema is where we model our data, where we describe the structure of the data, default values, and validation, then we take that schema and create a model out of it, a model is basically a wrapper around the schema, which allows us to actually interface with the database in order to create, delete, update, and read documents.
在 Mongoose 中,模式是我们对数据建模的地方,我们在其中描述数据的结构、默认值和验证,然后我们使用该模式并从中创建一个模型,模型基本上是模式的包装器,这允许我们实际与数据库交互,以便创建、删除、更新和读取文档。
Let's create a model from a schema.
让我们从模式创建一个模型。
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);
According to convetion first letter of a model name must be capitalized.
根据惯例,模型名称的首字母必须大写。
Let's create instance of our model that we created using mongoose and schema. also, interact with our database.
让我们创建我们使用猫鼬和模式创建的模型的实例。此外,与我们的数据库交互。
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);
});
So having both schama and modle mongoose makes our life easier.
因此,同时拥有 schama 和 modle mongoose 让我们的生活更轻松。