当前位置:  开发笔记 > 编程语言 > 正文

大讨论:NOSQL中数据库的设计精髓或者设计原则是什么?

我们先看看在mongodb下,Blog表是如何描述的:varBlogSchemenewdb.Schema({title:String,desc:String,author:String,body:String,tags:[String],count:{type:Number,default:0},hidde

我们先看看在mongodb下,Blog表是如何描述的:
var BlogScheme = new db.Schema({
title : String,
desc : String,
author : String,
body : String,
tags : [String],
count: { type:Number, default:0 },
hidden : { type: Boolean, default: false },
date : { type: Date, default: Date.now },
comments : [{ img: String, name: String, body: String, date: Date }],
meta : {
votes: Number,
favs: Number
}
});
  按照mongodb的设计,每篇Blog都是整篇存储的,与其它表基本没有关联,这也是NoSQL的精髓啊!但是这样子,我们该如何去统计Blog的标签tag呢?

这是我在网上摘抄的一篇文章。
其中关于NOSQL设计的一些原则。就是一篇文章就是一个表,基本上不与其他表联系,里面的评论直接放在了blog里面。我想问的是,如果这样做,怎么分页呢???
比如评论分页,,
还有就是nosql的设计原则是什么?有类似于关系型数据库的范式之说吗?

我还找到了一篇文章:
http://www.cnblogs.com/AllenDang/p/3507821.html#!comments
基本上其设计思路就是上面我提到的:将blog和评论放在一起。
这样做是减少了很多查询的。
但是出现了一个问题,如果用户的昵称变了。
那岂不是每一个这个用户评论的的blog都要去修改了????

关系型数据库,修改一下,然后join查询自然就是最新结果。
请问在mongodb里面该如何设计或者处理这种问题?

回复内容:

我们先看看在mongodb下,Blog表是如何描述的:
var BlogScheme = new db.Schema({
title : String,
desc : String,
author : String,
body : String,
tags : [String],
count: { type:Number, default:0 },
hidden : { type: Boolean, default: false },
date : { type: Date, default: Date.now },
comments : [{ img: String, name: String, body: String, date: Date }],
meta : {
votes: Number,
favs: Number
}
});
  按照mongodb的设计,每篇Blog都是整篇存储的,与其它表基本没有关联,这也是NoSQL的精髓啊!但是这样子,我们该如何去统计Blog的标签tag呢?

这是我在网上摘抄的一篇文章。
其中关于NOSQL设计的一些原则。就是一篇文章就是一个表,基本上不与其他表联系,里面的评论直接放在了blog里面。我想问的是,如果这样做,怎么分页呢???
比如评论分页,,
还有就是nosql的设计原则是什么?有类似于关系型数据库的范式之说吗?

我还找到了一篇文章:
http://www.cnblogs.com/AllenDang/p/3507821.html#!comments
基本上其设计思路就是上面我提到的:将blog和评论放在一起。
这样做是减少了很多查询的。
但是出现了一个问题,如果用户的昵称变了。
那岂不是每一个这个用户评论的的blog都要去修改了????

关系型数据库,修改一下,然后join查询自然就是最新结果。
请问在mongodb里面该如何设计或者处理这种问题?

nosql比较宽泛,不同的数据库设计原则不同。
比如mongoDB和redis都属于nosql,但是一个是文档型,一个是KV型,设计原则的区别特别大。

mongoDB的设计原则还是比较靠近关系型数据库,它的collection和table比较类似,也是insert、remove、update、find这几个基本操作,可以参考关系型数据库来设计。但是它比关系型关系灵活。
比如:一条微博可以插入9张图片,如果在MySQL中,可能这样设计:微博是一个table,图片信息是一个table,两只表做关联。或者这样设计:在微博那个table中加一个足够大的字符串类型的字段叫img_info,里面存放9张图片信息的json字符串。
而在mongoDB中,天生就是支持上述的第二种设计的。记住,是天生支持,也是就天生对img_info里面内容crud操作都异常方便。

然后回到你说的分页的问题:
分页主要就是用到2个函数:limit和skip
但是,数据量太大的时候,就不适合用skip分页了。
《MongoDB权威指南》中给出的解决方案是:获取上一页的最后一条数据,然后使用gt和limit获取下一页的数据。

关于redis的,@土豆2015 同学已经说的很详细了,就不累述了。

提醒@土豆2015 一下,mongoDB是将部分数据做内存映射,最大化利用内存,持久化还是会保存在磁盘中的。如果没有持久化,把mongoDB重启一下,数据不就都没有了啊。就算是redis这样纯内存型数据库,也是有数据持久化的。

你说的精髓的确是这样,但是只说对了一半,对于一篇博文来说评论的确可以做属性,但是评论的键你却没有选好,应该使用user_id来规避你说的昵称改变带来的问题。(你没有办法把所有东西全部塞到一个document里面对吧,你总有user_info集对吧)
所以mongodb的设计精髓并不是一味提倡你反范式,而是要懂得取舍。
再说说你问的统计tag的问题。
单看你的blog实体的tag设计成了list结构
就像是

tags = {
    "blog_id_111_tag": ["NBA", "姚明", "季后赛"],
}

要统计的办法其实很多,你应该是想统计topic_1下的博文有多少,topic_2下的博文又有多少对吧。其实也很好统计,在python中你可以使用字典推导式把这个tag反转。如下:

tag_mapper = {v:k for k in tags for v in tags[k]}
#这样你就得到了
{
    "NBA": "blog_id_111_tag",
    "姚明": "blog_id_111_tag",
    "季后赛": "blog_id_111_tag"
}

每篇博文都采取这样的方式统计,就能够统计出每个tag下面有哪些同类的博文了。

1.非关系型数据库产品的实质是关系型数据库产品的功能阉割版。通过阉割【关系】等功能,来获取更高的性能,以及更方便的使用性。

2.从上述实质出发,非关系型数据库产品适合用来做数据仓库。因为数据仓库中的数据的特点是量大、关系松散。

3.但是,非关系型数据库由于性能高,因此不少的人开始打它的主意,想把关系型数据也丢进来。这样做肯定有问题,因为你站在代码层上,试图自己在没有关系功能的非关系型数据库引擎上,自己来维护关系功能,肯定会付出昂贵的代价。这个代价可能是:
----1.非常低的效率。比如试图把一个分布在关系型数据库中多个属性表中的对象,组合回一个大对象放在非关系型数据库里,导致每次查询一个属性时,引擎不得不把整个大对象提取出来。
----2.非常脏的数据。由于大部分非关系型数据库产品无多表、库事务,因此有人通过创建单独的关系库,来维系两个不同对象的库的关系。但由于无事务,导致几个操作无法保证事务原子,因此经常产生冲突,导致数据“变脏”。

4.综上,当你满脑子都是如何处理强关系时,请不要坚持用非关系型数据库,不然你肯定会被坑。

对于关系型数据库来说,ACID是强一致性的四个要求(ACID:atomicity, consistency, isolation, durability;)

而BASE是NoSQL数据库通常对可用性及一致性的弱要求原则,BASE:Basically Available, Soft-state, Eventually Consistent。

nosql是不管关系结构的,但是我们可以利用已有的数据库结构来构造关系!

mongodb我没用过,我nosql用的redis.处理分页如下:

先有一个全量的blog list,只存blog.id。比如名字叫list:blog.
再有一个hash对应blog数据结构.命名可以这样blog:<#id>。
新建一个blog的时候,结合redis的transaction>>start
redis:rpush('list:blog', <#blog.id>);//先往list存id
redis:hmset('blog:'+<#blog.id>, 'title', ..., 'content', ....)//再存hash
transaction<<


分页的时候结合sort limit命令操作list和hash
sort list:blog limit 0 10 get # get blog:->title get blog:->content
当然还可以根据blog的某些属性进行sort
sort list:blog by blog:->createtime desc limit 0 10 get # get blog:->title get blog:*->content

至于评论的分页做法类似。

从你的问题上看出来,你的数据完全依赖mongodb,完全是依赖内存的,你的数据持久化是在哪里呢?

我来发表一下自己的见解吧:
讲要更新的数据放在一个集合,而不是将要显示的数据放在一个集合。那么将评论放在blog表就是错误的了。
因为无法解决这样的问题:
用户的昵称更新了怎么办。
因此,设计原则就是将要更新的放在一起。

去范式,分布式

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有