mongo中的外键?


94

在此处输入图片说明

如何在MongoDB中设计这样的方案?我认为没有外键!


9
您正在考虑相关问题,而不是面向文档的问题。:P
帕特

6
如果要使用关系数据库,为什么要使用MongoDB?
亚当·罗宾逊

47
:D我试图了解面向文档的方法;我该如何解决这个任务?
Mark Pegasov 2011年

如果您想获得面向文档的思维方式的答案,请参见stackoverflow.com/a/18637581/80428。当前接受的答案有效,但与NoSQL无关的是到文档存储的关系型数据库。
杰伊·威克

Answers:


27

您可能对使用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来建立文档之间的关系。


有文件的项目,我想绑定城市。我已经使用城市创建了收藏,但是我不知道如何将城市与物品绑定在一起。PS对不起,我的英语不好。
Mark Pegasov 2011年

UPD。我正在使用PHP作为编程语言,如果它是用Ruby编写的,该如何使用mongoid?
Mark Pegasov 2011年

1
@ЖирайрКазаросян:哦,我知道了:)作为Ruby开发人员,我只能在Ruby中思考:)恐怕我没有PHP和Mongo的经验,但是您可以查看以下链接:mongodb.org/display/DOCS/ …
Nerian 2011年

1
@ЖирайрКазаросян:我从实用的程序员那里用Ruby on Rails进行Web开发这本书学习了Ruby on Rails。您也可以通过此截屏视频codeschool.com/courses/rails-for-zombies
6

2
对于以后的读者来说,“表”是MongoDB中的“集合”。行是文档,列是字段...以防万一您混淆了。
cpu_meltdown

64

如何在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不是关系型的。没有标准的“标准格式”。您应该对数据库进行建模,使其适合存储的数据和要运行的查询。


2
好的,但是如何从学生收藏中获取姓名数据?db.student.find()将返回类似于课程的内容:[{课程:'bio101',标记:85}]
Mark Pegasov 2011年

@ЖирайрКазаросян:> db.foo.find({'_ id':ObjectId(“ 4df6539ae90592692ccc9940”)})-------------> {“ _id”:ObjectId(“ 4df6539ae90592692ccc9940”), “ group”:“ phones”}
Nerian 2011年

来自mongo的有关DBREF的文档:“除非您有令人信服的理由使用DBRef,否则请改为使用手动引用。”
kroiz

22

我们可以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字段包含_ids门课程。定义一对多关系很容易。但是,如果要检索学生的课程名称Jane,则需要执行另一项操作,以course通过检索文档_id

如果课程bio101被删除,我们需要执行另一项操作来更新文档中的courses字段student

更多:MongoDB模式设计

MongoDB的文档类型性质支持定义关系的灵活方法。定义一对多关系:

嵌入式文件

  1. 适合一对几。
  2. 优点:无需对另一个文档执行其他查询。
  3. 缺点:无法单独管理嵌入文档的实体。

例:

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 的父项logmsghost鉴于日志消息为数十亿,引用id可以节省很多空间。

参考文献:

  1. MongoDB模式设计的6条经验法则:第1部分
  2. MongoDB模式设计的6条经验法则:第2部分
  3. MongoDB模式设计的6条经验法则:第3部分
  4. 具有文档引用的一对多关系模型

19

摘自The Little MongoDB书

使用联接的另一种选择是对数据进行非规范化。从历史上看,非规范化是为性能敏感的代码保留的,或者应保留数据快照的时间(例如在审核日志中)。但是,随着NoSQL的日益普及(其中许多没有联接),作为规范化建模一部分的非规范化变得越来越普遍。这并不意味着您应该在每个文档中复制每条信息。但是,与其让担心重复数据驱动您的设计决策,不如考虑根据哪些信息属于哪个文档对数据进行建模。

所以,

student
{ 
    _id: ObjectId(...),
    name: 'Jane',
    courses: [
    { 
        name: 'Biology 101', 
        mark: 85, 
        id:bio101 
    },
  ]
}

如果它是RESTful API数据,则用指向课程资源的GET链接替换课程ID。


我认为这是正确的答案。除非您将关系数据存储在mongo中,否则在这种情况下,您确实应该质疑为什么要使用mongo。
杰伊·威克

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.