03、Mongodb 存储复杂对象

Par @Martin dans le
Tags :

Mongodb 做为一种 NoSql, 它的优点就是可以极好的与面向对象的语言相结合, 那面向对象的语言就会产生一些复杂的数据结构, 本节笔记就讲解如何将这些复杂对象映射到 Mongodb 里.

内嵌对象

所谓内嵌对象, 就是类似 Dict 那样, 把另一个对象做为 Dict 中某个字段的 value, 如:

{name: '张三', school: {name: '理工大学', city: '上海'}}


内嵌对象的__优点__就是__读取__非常快、方便, 可以一次性把相关的数据都读取出来.

再说说 内嵌对象 的__缺点__

就拿上面的 学生 => 学校 的例子来说, 如果存在几千几万个学生呢?
那 school: {name: ‘理工大学’, city: ‘上海’} 这种数据就存储了成千上万份, 不过这不是重点, 这种大数据量的存储还是没问题的, 但是..如果学校搬城市了呢? 从上海搬到南京了…那就要把所有的对象都更新次…这种更新的动作消耗就比较大了.

所以, 内嵌对象 的方式不适合这种 被内嵌的对象经常变动 的情况.

另外, 还有些复杂的对象是 内嵌对象 的方式无法表达的

例如存储 C 盘里所有目录/子目录的数据, 想一想, 如果用 内嵌对象 的方式, 每个目录都是对象, 它里面又包含了子对象, 子对象的里面还有子对象…这样下去无穷尽了…

再例如存储交友信息, 每个人都是对象, 如果用 内嵌对象, 那就会出现这种情况: A 里面有 B, B 里面又有 A…限入死循环了…

引用对象

为了解决 内嵌对象 方式的缺点, 引入了 引用对象 的方式.

这种方式的做法是, 在对象中只保存另一个对象的 _id 字段, 取数据的话先取出 _id, 然后根据 _id 再去取数据…

很明显这种方式的__缺点__就是取数据时要取__多次__(Mongodb 不支持 SQL 中的 Join, 即联合查询).

除了自己去实现这种引用关系外, Mongodb 也提供了自己的引用设计: DBRefs

语法如下:

{
    $ref:
    $id:
    $db:
 }


参数说明:

  • ref: 集合名称
  • id: 引用的 id
  • db: 可选, 数据库名称, 默认为当前所在库

如下面这个实例中用户数据文档中的 address 字段使用了 DBRef:

{
   '_id':ObjectId('53402597d852426020000002'),
   'name': 'Tom Benzamin'
   'address': {
       '$ref': 'address_home',
       '$id': ObjectId('534009e4d852427820000002'),
       '$db': 'w3cschoolcc'
   },
}


address DBRef 字段指定了引用的数据地址是在 w3cschoolcc 数据库下的 address_home 集合中, 其 _id 为 534009e4d852427820000002.

通过下面这种方式, 可以取出 address 数据:

var user = db.users.findOne({'name':'Tom Benzamin'})
db[user.address.$ref].findOne({'_id':(dbRef.$id)})


根据官方推荐, 当这种引用关系是建立在同一个集合中时, 就用第一种自己保存 _id 的方式, 如果是夸集合引用, 请使用 DBRef.