如何在MongoDB中设计这样的方案?我认为没有外键!
如何在MongoDB中设计这样的方案?我认为没有外键!
Answers:
您可能对使用Mongoid或MongoMapper之类的ORM感兴趣。
http://mongoid.org/docs/relations/referenced/1-n.html
在像MongoDB这样的NoSQL数据库中,没有“表”而是集合。文档在“集合”中分组。您可以在一个集合中拥有任何类型的文档以及任何类型的数据。基本上,在NoSQL数据库中,由您决定如何组织数据及其关系(如果有)。
Mongoid和MongoMapper所做的是为您提供方便的方法来轻松建立关系。查看我给您的链接,并询问任何事情。
编辑:
在mongoid中,您将这样编写方案:
class Student
include Mongoid::Document
field :name
embeds_many :addresses
embeds_many :scores
end
class Address
include Mongoid::Document
field :address
field :city
field :state
field :postalCode
embedded_in :student
end
class Score
include Mongoid::Document
belongs_to :course
field :grade, type: Float
embedded_in :student
end
class Course
include Mongoid::Document
field :name
has_many :scores
end
编辑:
> db.foo.insert({group:"phones"})
> db.foo.find()
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }
{ "_id" : ObjectId("4df6540fe90592692ccc9941"), "group" : "phones" }
>db.foo.find({'_id':ObjectId("4df6539ae90592692ccc9940")})
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }
您可以使用该ObjectId来建立文档之间的关系。
如何在mongodb中设计这样的表?
首先,要澄清一些命名约定。MongoDB使用collections
代替tables
。
我认为没有外键!
采用以下模型:
student
{
_id: ObjectId(...),
name: 'Jane',
courses: [
{ course: 'bio101', mark: 85 },
{ course: 'chem101', mark: 89 }
]
}
course
{
_id: 'bio101',
name: 'Biology 101',
description: 'Introduction to biology'
}
显然,简的课程列表指向一些特定的课程。数据库不对系统应用任何约束(即外键约束),因此没有“级联删除”或“级联更新”。但是,数据库确实包含正确的信息。
此外,MongoDB具有DBRef标准,可帮助标准化这些引用的创建。实际上,如果您查看该链接,它就有一个类似的示例。
我该如何解决这个任务?
需要明确的是,MongoDB不是关系型的。没有标准的“标准格式”。您应该对数据库进行建模,使其适合存储的数据和要运行的查询。
我们可以foreign key
在MongoDB中定义所谓的。然而,我们需要保持数据的完整性由我们自己。例如,
student
{
_id: ObjectId(...),
name: 'Jane',
courses: ['bio101', 'bio102'] // <= ids of the courses
}
course
{
_id: 'bio101',
name: 'Biology 101',
description: 'Introduction to biology'
}
该courses
字段包含_id
s门课程。定义一对多关系很容易。但是,如果要检索学生的课程名称Jane
,则需要执行另一项操作,以course
通过检索文档_id
。
如果课程bio101
被删除,我们需要执行另一项操作来更新文档中的courses
字段student
。
MongoDB的文档类型性质支持定义关系的灵活方法。定义一对多关系:
例:
student
{
name: 'Kate Monster',
addresses : [
{ street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
{ street: '123 Avenue Q', city: 'New York', cc: 'USA' }
]
}
像上面的student
/ course
示例。
适用于一到十亿,例如日志消息。
host
{
_id : ObjectID('AAAB'),
name : 'goofy.example.com',
ipaddr : '127.66.66.66'
}
logmsg
{
time : ISODate("2014-03-28T09:42:41.382Z"),
message : 'cpu is on fire!',
host: ObjectID('AAAB') // Reference to the Host document
}
实际上,a host
是a 的父项logmsg
。host
鉴于日志消息为数十亿,引用id可以节省很多空间。
参考文献:
使用联接的另一种选择是对数据进行非规范化。从历史上看,非规范化是为性能敏感的代码保留的,或者应保留数据快照的时间(例如在审核日志中)。但是,随着NoSQL的日益普及(其中许多没有联接),作为规范化建模一部分的非规范化变得越来越普遍。这并不意味着您应该在每个文档中复制每条信息。但是,与其让担心重复数据驱动您的设计决策,不如考虑根据哪些信息属于哪个文档对数据进行建模。
所以,
student
{
_id: ObjectId(...),
name: 'Jane',
courses: [
{
name: 'Biology 101',
mark: 85,
id:bio101
},
]
}
如果它是RESTful API数据,则用指向课程资源的GET链接替换课程ID。
如果字段值与它的ForeignKey不匹配,ForeignKey的目的是防止创建数据。为了在MongoDB中完成此任务,我们使用Schema中间件来确保数据的一致性。