mongodb是NoSQL的表明,从使用关系型数据库(MySQL)到使用非关系型数据库(mongodb),其中的一些之前的设计的思惟惯性老是在不知不觉的影响着本身的决策。设计的思想有共同之处,也有很大的不一样。mongodb的优点在于他表示数据的方式很是丰富。下面就来总结一些设计的原则和方法。mongodb
schema的设计最重要的不是当前设计的可扩展性,对设计的可读性,仍是说原来的设计三范式。最重要的在于,你的app通常展示出来的数据是什么结构,就设计成什么样。取出即用。举个例子来讲,若是设计一个博客的schema,按照原来的方法, 你可能会设计成:数据库
posts { _id: , title: , body: , author: , date: } comments { _id: , post_id: , author: , order: } tags { _id: , tag: , post_id: }
可是更好的设计是:json
{ _id: , author: , body: , comments : [ { body: , email: , author: , }, ... { ... } ], date: , tags: [ ... ], title: }
尽量的减小数据库数据修改的难度(减小数据冗余)数组
最小化数据库设计扩展的改动app
避免数据库访问时的歧义数据库设计
在mongodb中:post
默认的来讲设计的时候是要避免数据冗余的性能
不存在这样的问题,由于mongo中的schema很是灵活,你能够随时的改动测试
因为设计的时候就尽量的按照应用须要的数据的形式设计,取出即用,因此第三个问题出现的几率也比较少设计
在mongo中,最常常思考的问题就是,没有外键怎么保持数据一致性?正如上述博客的第一种设计中,你在新插入一个评论的时候,数据库是不会保证你这个post_id是否是真在在posts这个collection里面有对应值。
解决的办法就是像第二种设计中的作法,把他嵌入在posts这个collection.因为这个时候评论已是post的一部分,就不再用担忧插入的评论没有对应到一篇博客的问题。
在目前,mongodb是不支持事务的。也就是说,若是你一个业务须要修改好几条记录,你是没办法保证当其中一个操做失败的之后将其它操做回滚的,这种时候又应该怎么办?
虽然mongo没有提供事务,可是他提供了很是丰富的原子操做,咱们应该充分利用这一点。在关系型数据库中,你可能有几张表,而后要经过join的方式去连接。因此你须要事务去同时修改几张表。可是在mongo中,在设计的时候你已经prejoin了(就是你已经把它们都嵌入在了同一个collection),你只须要直接一次修改整个post就能够实现事务的效果。
总的来讲,解决的办法有三个:
重建你的设计,使得你能经过原子操做一次把它们都修改完
在你的软件中实现锁的机制,用寻找和修改写一系列的测试来实现。
在大量的数据或者不严格的场景中,容忍这种错误
好比说应聘者和简历的关系。除非嵌在一块儿会致使你的数据大于16MB(mongo的限制),你都应该嵌在一块儿。作好的作法就是将一个比较少使用的嵌入一个常常食用的当中。
好比说城市和人的关系,博客和评论
对于像城市和人的关系这样的,一个城市实在是对应了太多太多的人。若是将人嵌入在城市中,不太合适。在城市信息嵌入在人中就更不合适了,由于还会产生大量数据冗余,更新信息也特别麻烦。这种状况下最好的作法就是分开两个collection,而后人的collection中每一条都有一个city字段,来对应城市collection中的一条。
若是是像博客和评论这样一个对应的不是特别多的时候,最好的最法仍是嵌进去
例如书和做者的关系,老师和学生的对应关系
对于像书和做者这样,比较少对应比较少的,一个可行的作法就是分开两个collection。书collection中存一个authors数组,做者 collection中存一个books数组,互相对应。这种作法很差的地方就在与要手动维护数据一致性。另外一个作法就是嵌在一块儿,这样会有性能的提高,不过这种作法会致使数据冗余,看具体的状况来取舍。特别的像老师和学生这种关系,最好最好就是不要将老师嵌在学生中,由于极可能一个新来的老师就尚未学生,这样你就没办法把这位老师加入到系统中。
一个典型的场景就是像amazon这样的电商,一个商品分类下可能有不少个子分类。
其中的一个作法就是创建一个分类的collection,而后每一个分类有一个parent_id字段,可是这样不便于找到他全部的祖先。因此比较好的作法是再加一个ancesters的数组字段,记录他全部的祖先的id,这样就能方便的查询到他的祖先和后代。
提升读的效率。这意味着你要获取数据只须要查询一次数据库就好了。
若是一个数据量特别大(大于16M),好比读入一个100多M的mp4文件。这种状况下就须要用到GRIDFS.原理就是把他分割成一个一个小的块