面向.Net开发人员的MongoDB-无框架概念

现在是时候看一下NoSQL的“无框架”到底是什么意思了,当我们对比面向文档数据库和一个更传统的关系型数据库SQLSERVER时,我们将毫无疑问的选择MongoDB。

Schema, MongoDB vs RDBMS(关系型数据库)

你肯定已经熟悉了在关系型数据库中创建一个Schema(表结构)了,不如SQL SERVER。让我们看一下MongoDB中的术语

RDBMS vs MongoDb

Table --> Collection Row --> Document Column --> Field Join --> Embedded document Join --> Link/Reference Index --> Index

Table vs Collection

 Collection是一个命名的包裹,也就是你放Document的地方. 它在第一次使用时被创建. Collections是无框架的, 无框架意味着没人阻止你把不同的实体混在一起放进Collection. 你可以有一个叫Cars的collection用来保存汽车信息,同时也可以保存驾驶员信息,水果信息等等完全不同的成员。

Car: {registrationNo: 'ABC123', make: 'VOLVO', model: 'XC90'} vs Driver: {socSecNo: 12345, firstname: 'Daniel', lastname: 'Wertheim', license: 'AB'} VS Fruit: {type: 'APPLE', name: 'Royal Gala', color: 'Red', season: 'Autumn'}

在MongoDB中并不会有潜在的Schema,比如这个Collection拥有这些字段: registrationNo, make, model, socSecNo, firstname, lastname, license, type, name, color, season, 比如firstname字段nvarchar(50) NULL这种的. 当然在关系型数据库里,你也可以仿照这样建表, key-value 表, 就像我在SisoDb做的.

无框架是不是意味着我再也不用关心框架了?

并非如此! 理论上可能是, 但是我会说不行! 怎么样去设计你的Documents应该跟你怎么使用它们相关. 当下什么才是最重要的? 读写性能? 你是不是在使用静态语言比如 C# 你想不想预先创建类来定义你的存储实体? 如果是的那么定义 Cars 和 Fruits 在同一个collection里,将使你不得不在应用程序的查询里面增加相应的判断逻辑. Document D1 到底是Car还是个 Fruit?

假设你正在写一个碉堡了的APP, 你很可能会有大量数据. 你到时候将不得不在Document上加索引,搞不好还要加Sharding-Key来分片 ,把不同类型的数据放在同一个Collection里面肯定会给你带来麻烦, 因为sharding-key需要在两处都存在.

你同样要考虑后期维护. 你没办法检查Schema了,所以如果你的Collection忽然收到一个内容非常不一样的Document时咋办? 维护你APP的人如果仅仅检查一些特定Collection里面的某些Documents,他很可能不会意识到这个.

Row vs Document & Join vs Embedded document(内嵌文档)

同时考虑ROW和Documents来当作一个实体的实例可能会简单点。在传统的格式化关系型数据库中, 把所有的数据都包含在一行里面,只有一种可能,那就是这个实体是一个“独立的死实体”,也就是没有任何关联.让我举个例子,有一个订单表Order, 一个Order 可以包含多个OrderLine 实体. 关系型数据库中这会被设计成 Order-表 和OrderLine-table表, 两者相互关联。Order-Line有个外键指向Order-table的一条记录. 在面向对象数据库中,你更可能把Order-Line包含在Order里面; 因此我们储存的数据可以同时看到Order和Order-line. 因此在Mongo数据库里,你不需要用Join去获取一个Order的全部信息.

Relational DB Order {#Id, Date, CustomerNo, ...} --<1:N> -- OrderLine {#OrderId, #ArticleNo, Quantity, Price, Tax } Document DB: Order {#_id, date, customerNo, ..., lines: [ {articleNo, quantity, prixe, tax}, {articleNo, quantity, prixe, tax}]}

比如现在你需要获取包含某个article number.的所有订单 ,在关系型数据库里,你大概会这么去写

select [columns of interest] from dbo.Order as O inner join dbo.OrderLine as Ol on Ol.OrderId = O.Id where Ol.ArticleNo = @articleNo;

MongoDB里面长这样:

db.orders.find({'lines.articleNo'=articleNo})

那如果在外面这个Model里面增加一个新Customer会发生什么? 稍安勿躁. 我在下面: “Join vs Link/Reference“里详细解释.

Index vs Index

Mongo里面也有索引的概念 ,在 articleNo上建一个下面的索引上面的查询会更快:

db.ensureIndex({'lines.articleNo': 1})

至于索引我们可以看别的文章深入研究. 暂时我们只要知道Mongo里也有索引,并且影响你Docunent的设计就够了. 同时也注意它跟关系型数据库的不一样。 你必须确保索引存在可以获取一次有效的JOIN,同时索引也得存在与ArticleNo上.

Join vs Link/Reference

上面我们稍微领略了一下“Join vs Embed document”, 知道Document是如何内嵌来去除JOIN的. 如果你是从关系型数据库世界来的,现在你一定从椅子上跳起来了. 立马想到: 数据重复, 关联约束, 等等. 你当然可以把他们分成不同的Document并包含_id的值在里面用作应用级别的关联.所以现在你有两个选择: 内嵌VS关联.

何时内嵌何时关联?

老生常谈,这跟应用场景相关. 我会说面向Document数据库是以 用例中心 方式存储的而不是 小数据单元的格式化表格存储. 一个传统的例子是. 如果我们有个博客系统,相应的有评论,有的评论的回复, 你可以把所有的博客评论信息都存储成一个TREE:

blogpost: { _id: ..., title: ..., content: ..., ts: ..., author: ..., comments: [ {title: ..., ts: ..., author: ..., comment: ...}, {title: ..., ts: ..., author: ..., comment: ..., replies:[ {title: ..., ts: ..., author: ...}, {title: ..., ts: ..., author: ...} ] } ] }

你很可能如果你经常单独的博客一组完全展示所有的信息,这个就很好用.但是如果有大量的评论怎么办? . 你很可能会达到Document的存储上线16MB。或者换成关联?在评论的Document里面存一个博客的Id:

blogpost: { _id: 'fooId', title: ..., content: ..., ts: ..., author: ...} comments: {_id: ..., blogpostId: 'fooId', replies: [ {title: ..., ts: ..., author: ..., comment: ...}, {title: ..., ts: ..., author: ..., comment: ...}] }

但是又来了,你还是可能会触及存储上限. 或者你可能想操作某一条评论. 所以把他们分开.

blogpost: { _id: 'fooId', title: ..., content: ..., ts: ..., author: ..., comments: ['commentId1', 'commentId2', ...] } comment: {_id: 'commentId1', blogpostId: 'fooId'} comment: {_id: 'commentId2', blogpostId: 'fooId'}

因为我们两边都引入了对方的Id,因此可以两个方向访问数据. 我们可以单独展示博客,单独操作评论,列出所有评论. 但是,但是,但是,又来了,这符不符合你的需求? 这个例子可能适合. 但是在相似的情景中,一个博客界面含有其他别的查询有可能会影响你的性能. 设计总是上下文相关的. 你有可能会需要把他们混合起来使用, 选择关系型数据库还是面向Document数据库? 你可能会制造重复数据,为具体的用例创建具体页面. 一个只显示部分评论的界面,比如最近10条.

我们继续订单的例子. 我们可能会有一个Collection叫Custome,它并未被内嵌进Order, 但是部分Customer会被内嵌. 就算被内嵌的都是唯一的,所以你可能需要在应用里面把Customer关联起来.

order: {_id: ..., customerId: ...m customerNo: ..., ...}

总结

我们已经快速领略了无框架的概念. 用MongoDB来举例, 你的应用依然有概念上的Schema,但是你的数据库已经不强制你为Collection/数据集创建Schema了. 我想用一句名言来结束这篇文章:

“能力越大,责任越大”

以上.让我们期待我有时间做一个关于此更加“无理论”的讨论吧。

//Daniel

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值