如何在MongoDB中设计这样的方案?我认为没有外键!
答案 0 :(得分:57)
如何在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'
}
显然,Jane的课程列表指向某些特定课程。数据库不对系统应用任何约束(,即:外键约束),因此没有“级联删除”或“级联更新”。但是,数据库确实包含正确的信息。
此外,MongoDB有一个DBRef standard,可以帮助标准化这些引用的创建。事实上,如果你看一下这个链接,它有一个类似的例子。
我该如何解决这个问题?
要明确,MongoDB不是关系型的。没有标准的“正常形式”。您应该根据您存储的数据和要运行的查询对数据库建模。
答案 1 :(得分:21)
您可能有兴趣使用像Mongoid或MongoMapper这样的ORM。
http://mongoid.org/docs/relations/referenced/1-n.html
在像MongoDB这样的NoSQL数据库中,没有'tables'而是文档。文档在集合中分组。您可以在一个集合中包含任何类型的文档 - 包含任何类型的数据。基本上,在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来处理文档之间的关系。
答案 2 :(得分:14)
使用连接的另一种替代方法是对数据进行非规范化。从历史上看,非规范化是为了保留的 对性能敏感的代码,或者应该对数据进行快照(如在审计日志中)。然而,永远 NoSQL的日益普及,其中许多没有连接,非规范化作为正常建模的一部分正在变得越来越多 越来越普遍。这并不意味着您应该复制每个文档中的每条信息。然而, 而不是担心重复数据会驱动您的设计决策,而是考虑根据内容对数据进行建模 信息属于什么文件。
所以,
student
{
_id: ObjectId(...),
name: 'Jane',
courses: [
{
name: 'Biology 101',
mark: 85,
id:bio101
},
]
}
如果是RESTful API数据,请将课程ID替换为课程资源的GET链接
答案 3 :(得分:12)
我们可以在MongoDB中定义所谓的foreign key
。但是,我们需要维护数据完整性 BY OURSELVES 。例如,
student
{
_id: ObjectId(...),
name: 'Jane',
courses: ['bio101', 'bio102'] // <= ids of the courses
}
course
{
_id: 'bio101',
name: 'Biology 101',
description: 'Introduction to biology'
}
courses
字段包含_id
个课程。 很容易定义一对多的关系。但是,如果我们想要检索学生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
}
实际上,host
是logmsg
的父级。引用host
id可以节省大量空间,因为日志消息是非常广泛的。
参考文献:
答案 4 :(得分:1)
简答: 您应该使用 ObjectId 属性在集合之间使用“弱引用”:
<块引用>引用通过包含链接或 从一个文档到另一个文档的引用。应用程序可以解决 这些引用访问相关数据。大体上,这些是 标准化数据模型。
https://docs.mongodb.com/manual/core/data-modeling-introduction/#references
这当然不会检查任何参照完整性。您需要在您这边(应用程序级别)处理“死链接”。
答案 5 :(得分:0)
ForeignKey的目的是在字段值与其ForeignKey不匹配时阻止创建数据。为了在MongoDB中完成此任务,我们使用Schema中间件来确保数据的一致性。