原文:http://blog.mongodb.org/post/87200945828/6-rules-of-thumb-for-mongodb-schema-design-part-1

By William Zola, Lead Technical Support Engineer at MongoDB

“我有丰富的sql使用经验,但是我是个MongoDB的初学者。我应该如何在MongoDB中针对一对多关系进行建模?”这是我被问及最多的问题之一。

我没法简单的给出答案,因为这有很多方案去实现。接下来我会教导你如何针对一对多进行建模。

这个话题有很多内容需要讨论,我会用三个部分进行说明。在第一部分,我会讨论针对一对多关系建模的三种基础方案。在第二部分我将会覆盖更多高级内容,包括反范式化和双向引用。在最后一部分,我将会回顾各种选择,并给出做决定时需要考虑的因素。

很多初学者认为在MongoDB中针对一对多建模唯一的方案就是在父文档中内嵌一个数组子文档,但是这是不准确的。因为你可以在MongoDB内嵌一个文档不代表你就必须这么做。

当你设计一个MongoDB数据库结构,你需要先问自己一个在使用关系型数据库时不会考虑的问题:这个关系中集合的大小是什么样的规模?你需要意识到一对很少,一对许多,一对非常多,这些细微的区别。不同的情况下你的建模也将不同。

Basics: Modeling One-to-Few

一对很少

针对个人需要保存多个地址进行建模的场景下使用内嵌文档是很合适,可以在person文档中嵌入addresses数组文档:

这种设计具有内嵌文档设计中所有的优缺点。最主要的优点就是不需要单独执行一条语句去获取内嵌的内容。最主要的缺点是你无法把这些内嵌文档当做单独的实体去访问。

例如,如果你是在对一个任务跟踪系统进行建模,每个用户将会被分配若干个任务。内嵌这些任务到用户文档在遇到“查询昨天所有的任务”这样的问题时将会非常困难。我会在下一篇文章针对这个用例提供一些适当的设计。

Basics: One-to-Many

一对许多

以产品零件订货系统为例。每个商品有数百个可替换的零件,但是不会超过数千个。这个用例很适合使用间接引用---将零件的objectid作为数组存放在商品文档中(在这个例子中的ObjectID我使用更加易读的2字节,现实世界中他们可能是由12个字节组成的)。

每个零件都将有他们自己的文档对象

每个产品的文档对象中parts数组中将会存放多个零件的ObjectID :

在获取特定产品中所有零件,需要一个应用层级别的join

为了能快速的执行查询,必须确保products.catalog_number有索引。当然由于零件中parts._id一定是有索引的,所以这也会很高效。

这种引用的方式是对内嵌优缺点的补充。每个零件是个单独的文档,可以很容易的独立去搜索和更新他们。需要一条单独的语句去获取零件的具体内容是使用这种建模方式需要考虑的一个问题(请仔细思考这个问题,在第二章反反范式化中,我们还会讨论这个问题)

这种建模方式中的零件部分可以被多个产品使用,所以在多对多时不需要一张单独的连接表。

Basics: One-to-Squillions

一对非常多

我们用一个收集各种机器日志的例子来讨论一对非常多的问题。由于每个mongodb的文档有16M的大小限制,所以即使你是存储ObjectID也是不够的。我们可以使用很经典的处理方法“父级引用”---用一个文档存储主机,在每个日志文档中保存这个主机的ObjectID。

以下是个和第二中方案稍微不同的应用级别的join用来查找一台主机最近5000条的日志信息

所以,即使这种简单的讨论也有能察觉出mongobd的建模和关系模型建模的不同之处。你必须要注意一下两个因素:

Will the entities on the “N” side of the One-to-N ever need to stand alone?

一对多中的多是否需要一个单独的实体。

What is the cardinality of the relationship: is it one-to-few; one-to-many; or one-to-squillions?

这个关系中集合的规模是一对很少,很多,还是非常多。

Based on these factors, you can pick one of the three basic One-to-N schema designs:

基于以上因素来决定采取一下三种建模的方式

一对很少且不需要单独访问内嵌内容的情况下可以使用内嵌多的一方。

一对多且多的一端内容因为各种理由需要单独存在的情况下可以通过数组的方式引用多的一方的。

一对非常多的情况下,请将一的那端引用嵌入进多的一端对象中。

下一次我们将会看到如何使用双向关系和反范式化去提升以上三种基本方案的性能。

mongo设计(一)的更多相关文章

  1. mongo设计(三)

    原文:http://blog.mongodb.org/post/88473035333/6-rules-of-thumb-for-mongodb-schema-design-part-3 By Wil ...

  2. mongo设计(二)

    原文:http://blog.mongodb.org/post/87892923503/6-rules-of-thumb-for-mongodb-schema-design-part-2 By Wil ...

  3. mongo学习笔记2--索引及表设计

    -背景: 鉴于我们使用mongo作为数据库,期间少不了需要添加索引和对业务表进行设计.因此以下我对mongo索引及表设计原则做了一些分享.希望对大家有用,如有错误还望指正~ MongDB的索引类型简介 ...

  4. mongo实体设计1 tag

    public class TagProperty { private String type; private int count; } @Document(collection = "ta ...

  5. Lind.DDD.Repositories.Mongo层介绍

    回到目录 之前已经发生了 大叔之前讲过被仓储化了的Mongodb,而在大叔开发了Lind.DDD之后,决定把这个东西再搬到本框架的仓储层来,这也是大势所趋的,毕竟mongodb是最像关系数据库的NoS ...

  6. MongoDB学习笔记~ObjectId主键的设计

    回到目录 说一些关于ObjectId的事 MongoDB确实是最像关系型数据库的NoSQL,这在它主键设计上可以体现的出来,它并没有采用自动增长主键,因为在分布式服务器之间做数据同步很麻烦,而是采用了 ...

  7. MongoDB学习笔记~Mongo集群和副本集

    回到目录 一些概念 对于Mongo在数据容灾上,推荐的模式是使用副本集模式,它有一个对外的主服务器Primary,还有N个副本服务器Secondary(N>=1,当N=1时,需要有一台仲裁服务器 ...

  8. 开发高效的Tag标签系统数据库设计

    需求背景 目前主流的博客系统.CMS都会有一个TAG标签系统,不仅可以让内容链接的结构化增强,而且可以让文章根据Tag来区分.相比传统老式的Keyword模式,这种Tag模式可以单独的设计一个Map的 ...

  9. c#开发Mongo笔记第八篇

    到今天为止,Mongo开发的权限管理系统功能就做完了,剩下的就是完善构架,优化结构,只是现在c#操作Mongo的各种操作基本都掌握了 说到权限管理系统,其实再简单不过了,在关系型数据的是时代,我们通常 ...

随机推荐

  1. jquery中attr()与prop()函数用法实例详解(附用法区别)

    本文实例讲述了jQuery中attr()与prop()函数用法.分享给大家供大家参考,具体如下: 一.jQuery的attr()方法 jquery中用attr()方法来获取和设置元素属性,attr是a ...

  2. php 记住密码自动登录

    当我们登录网站管理后台的时候,会有提示说记住登录状态,记住我等这样的提示,这个选项有什么用呢?如果选中了记登录状态后,下次在浏览这个网站后 台时就不用在填写用户名和密码了,在去登录了.下面写了一小代码 ...

  3. yii中使用active record进行关联显示

    model中: view中:

  4. Child Process

    Child Process child_process 这个模块可以生成一个子进程.nodejs提供了好几个API,本质上都是调用child_process.spawn(): const spawn ...

  5. nginx的请求接收流程(一)

    今年我们组计划写一本nginx模块开发以及原理解析方面的书,整本书是以open book的形式在网上会定时的更新,网址为http://tengine.taobao.org/book/index.htm ...

  6. Windows消息拦截技术的应用(作者博客里有许多相关文章)

    民航合肥空管中心 周毅 一.前 言 众所周知,Windows程式的运行是依靠发生的事件来驱动.换句话说,程式不断等待一个消息的发生,然后对这个消息的类型进行判断,再做适当的处理.处理完此次消息后又回到 ...

  7. MFC 操作控件数据

    在MFC中有多种获取控件数据的方法 1.GetWindowText()和SetWindowText()函数   ],ch2[],ch3[]; GetDlgItem(IDC_EDIT1)->Get ...

  8. Linux进程间通信——使用匿名管道

    在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据.   一 ...

  9. OSCHina技术导向:web内容管理系统Magnolia

    Magnolia简介: Magnolia CMS是一家瑞士公司自2003年起发布的一个基于Java的开源内容管理系统.它适合且已被使用在以下领域:电子商务(例如:COOP.Migros.Rossman ...

  10. C和指针 (pointers on C)——第五章:操作符和表达式

    第五章 操作符和表达式 这一章假设没做过玩过单片机.汇编的话,读起来可能比較吃力,尤其是在移位运算符.位运算符应用上.另外多注意一下左值和右值的理解. 总结: 算术操作符.赋值操作符.关系操作符.条件 ...