MongoDB DBRef和手动引用(Manual References)

2,635 阅读4分钟
原文链接: blog.csdn.net

http://www.cnblogs.com/alab/archive/2012/07/25/2608905.html

MongoDB之数据建模

MongoDB与关系型数据库的建模还是有许多不同,因为MongoDB支持内嵌对象和数组类型。MongoDB建模有两种方式,一种是内嵌(Embed),另一种是连接(Link)。那么何时Embed何时Link呢?那得看两个实体之间的关系是什么类型。

一对一的关系:Embed,比如用户信息集合有Address字段,Address字段有省、市、县三个字段。建模如下:

QQ截图20120725190049

 

 

QQ截图20120725185306

 

 

 

 

 

 

一对多关系:一篇文章有多条评论,为1对多关系

QQ截图20120725185727 QQ截图20120725190617

由于MongoDB对单个文档(document)有大小限制16M(高于v1.8),设计时也要将这个限制纳入考虑中。

多对多关系:学生和课程是多对多的关系,一个学生可以选多门课程,一门课程有多名学生参与。

QQ截图20120725190110

多对多使用了连接(Linking),连接是通过引用(References)来连接两个集合。MongoDB References有两种:一种是 手动引用(Manual References),另一种是DBRefs。

Manual References:

QQ截图20120725192451(user集合)

QQ截图20120725192634(post集合)

红框地方就是Manual References,如果想查询一篇文章的作者信息,首先在post集合找出那篇文章,然后在user集合查找出用户的全部信息。但是假如有这么一个场景:用户可以对图片,文章等各种资源评论,所有的评论都放在comment集合中,如果只是使用Manual References,就分不清楚评论到底是属于哪类资源了,图片?文章?。所以有了DBRef。

DBRef的形式:

{ $ref : <value>, $id : <value>, $db : <value> }
$ref:集合名称;$id:引用的id;$db:数据库名称,可选参数。
DBRef只能有这三个键,不能再添加其他键。
可以看到DBRef的结构比Manual References的复杂,占用的空间大,但是功能也强大,如果要跨数据库连接,上面讲的评论集合的例子,都得需要使用DBRef,MongoDB提供了函数来解析DBRef,不用像Manual References需要自己手动写两次查询。
 
关于MongoDB的数据建模MongoDB官网也给出了一些建议。这些建议都是提供了一些参考,实际建模需要根据具体的需求来分析,分析数据经常会执行哪些操作(排序,查找,修改)来选择Embed和Link。

DBRefs 示例:

[plain] view plain copy print?
  1. db.foo.find()  
db.foo.find()
[plain] view plain copy print ?
  1. {  
  2.     "_id" : ObjectId("59379e0c2e7a03e326cc7553"),  
  3.     "arr" : [  
  4.         {  
  5.             "x" : 1  
  6.         },  
  7.         {  
  8.             "y" : 2  
  9.         }  
  10.     ]  
  11. }  
{
    "_id" : ObjectId("59379e0c2e7a03e326cc7553"),
    "arr" : [
        {
            "x" : 1
        },
        {
            "y" : 2
        }
    ]
}
建立一个DBRefs, [javascript] view plain copy print?
  1. db.test.insert({value: {$ref: "foo", $id: ObjectId("59379e0c2e7a03e326cc7553")}, a: 1})  
  2.   
  3. db.test.find().pretty()  
  4.   
  5. {  
  6.     "_id" : ObjectId("5937a3df2e7a03e326cc7559"),  
  7.     "value" : DBRef("foo", ObjectId("59379e0c2e7a03e326cc7553")),  
  8.     "a" : 1  
  9. }  
  10.   
  11. db.test.findOne({a: 1}).value.fetch()  
  12.   
  13. {  
  14.     "_id" : ObjectId("59379e0c2e7a03e326cc7553"),  
  15.     "arr" : [  
  16.         {  
  17.             "x" : 1  
  18.         },  
  19.         {  
  20.             "y" : 2  
  21.         }  
  22.     ]  
  23. }  
db.test.insert({value: {$ref: "foo", $id: ObjectId("59379e0c2e7a03e326cc7553")}, a: 1})

db.test.find().pretty()

{
    "_id" : ObjectId("5937a3df2e7a03e326cc7559"),
    "value" : DBRef("foo", ObjectId("59379e0c2e7a03e326cc7553")),
    "a" : 1
}

db.test.findOne({a: 1}).value.fetch()

{
    "_id" : ObjectId("59379e0c2e7a03e326cc7553"),
    "arr" : [
        {
            "x" : 1
        },
        {
            "y" : 2
        }
    ]
}

如果是数组,则需要用以下方式:

[javascript] view plain copy print?
  1. db.test.findOne({a: 1}).value[0].fetch();  
db.test.findOne({a: 1}).value[0].fetch();