MongoDB的数据建模

MongoDB是一种面向Document的NoSQL数据库,如果我们还是按照RDB的方式来思考MongoDB的数据建模,则不能有效地利用MongoDB的优势;然而,我们也不能因为Document的灵活性,就可以在设计之初放任自流。

适度的建模是非常有必要的,尤其对于相对复杂的关联关系。因为在MongoDB中,处理这种关联关系既可以使用Link,也可以使用Embedded。

我们要评价一种决策,不能将其与具体的上下文割裂开来做判断,那种单纯说A技术要比B技术好的做法,就像小孩子看卡通片里的人物只知道说谁是好人谁是坏人一般的幼稚。世界上没有一种完美至善的技术,关键还是要结合场景来看使用是否得法。

例如使用Embedded方式,就各有优缺点。举例来说,倘若我们采用Embedded方式将Addresses作为Person对象内部的数组:

{
  name: 'Kate Monster',
  ssn: '123-456-7890',
  addresses : [
     { street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
     { street: '123 Avenue Q', city: 'New York', cc: 'USA' }
  ]
}

当我们在查询Person的信息时,要获取其内嵌的属性细节,我们无需再执行多次查询。倘若我们改变一下领域场景,需要开发一个任务跟踪系统。如果我们将Tasks的信息嵌入到Person对象中,当我们面对以下需求:

  • 显示所有明天到期的任务
  • 显示所有未完成的任务

采用这种Embedded就不那么令人愉快了。

如果采用Link方式,情况就完全不同了:

//Tasks
[
    {
        _id: ObjectID('AAAA'),
        task_number: 1234,
        taks_name: 'Prepare MongoDB environment',
        due_date: '2017-01-15'
    },
    {
        _id: ObjectID('BBBB'),
        task_number: 1235,
        taks_name: 'Import Test Data',
        due_date: '2017-02-15'
    },
]

//Persons
{
  name: 'Kate Monster',
  role: 'Manager',
  tasks : [
    ObjectID('AAAA'),
    ObjectID('BBBB')
  ]
}

有得必有失,当我们需要查询Person承担的Tasks时,采用这种方式,就需要采用application-level join方式执行两次查询。

这种建模方式还带来另一种可能,就是原本Person->Tasks的one-to-N关系就可以变为N-to-N关系,因为一个Task可以被多个Person所拥有。如果采用Embedded方式,则会导致Task数据的冗余。

在文章 6 Rules of Thumb for MongoDB Schema Design中,作者将这种1对N关联实现的判断依据划分为三种形式:

  • one-to-few
  • one-to-many
  • one-to-squillions

但我认为该怎么实现关联,应该从Entity之间的领域关系来判断,我们可以引入DDD的Aggregation设计概念作为建模的依据。简单来说,如果使用Embedded,可以认为该Entity处于Aggregation边界之内,对外应该通过Aggregation Root来访问。文章 6 Rules of Thumb for MongoDB Schema Design的说法就是:

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

如果是Stand Alone,就意味着该Entity可以成为一个独立的Aggregation,然后再通过ID与另外一个Aggregate关联。

在SegmentFault上则有人做了如此总结

  • FirstClass (比如“User”这种) 应该用独立的Collection
  • "条目类型"的,应该 embedded
  • 两个模型之间如果是包含关系,用 embedded
  • 多对多关系,用 link(类似sql里面的foregin key)
  • 如果一个模型,其可能存的对象很少,那么就用独立的collection,这样有助于mongodb server做缓存
  • embedded方式不利于做复杂的关联,复杂的查询
  • embedded方式性能很有优势,如果你有“性能”方面的要求,可以考虑用embbed

原文发布于微信公众号 - 逸言(YiYan_OneWord)

原文发表时间:2017-01-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏CSDN技术头条

MongoDB的设计模式策略

MongoDB是一项通用工具,但它也并非完美。针对某些MongoDB不适用的场合,有时可选用设计模式来加以应对。 MongoDB是一个NoSQL文档数据库,在大...

1856
来自专栏智能大石头

借助Redis做秒杀和限流的思考

最近群里聊起秒杀和限流,我自己没有做过类似应用,但是工作中遇到过更大的数据和并发。 于是提出了一个简单的模型: var count = rds.inc(key)...

4914
来自专栏苦逼的码农

加锁还是不加锁,这是一个问题

上次我说过, 我们这个线程的世界是个弱肉强食的地方, 大家为了争抢资源大打出手,时不时闹出些内存数据互相被覆盖的事故, 给人类带了无穷的烦恼。

1065
来自专栏钱坤的专栏

cache 淘汰算法:LIRS 算法

LIRS 算法是非常优秀的 cache 淘汰算法,被用于 mysql 5.1之后的版本,这篇文章主要来源于对 LIRS 的发表论文的翻译。

9613
来自专栏涂小刚的专栏

从 PageRank Example 谈 Spark 应用程序调优

在做PageRank测试时,发现有很多有趣的调优点,想到这些调优点可能对用户来说是普遍有效的,现把它整理出来一一分析,以供大家参考。

7803
来自专栏一名叫大蕉的程序员

简约的JAVA版本MapReduce和日常No.25

昨天做了一个小调查,说看看想看些啥。大概的分布是这样的,一个1代表一个投票。看来还是2、3比较多。 11111 希望看到"算法"回复1。 111...

1775
来自专栏人工智能LeadAI

TensorFlow分布式全套(原理,部署,实例)

TF的实现分为了单机实现和分布式实现,在分布式实现中,需要实现的是对client,master,worker process不在同一台机器上时的支持。数据量很大...

5616
来自专栏程序人生

上帝说:要有一门面向未来的语言,于是有了 erlang

今个谈谈 erlang。 这些文章流于表面,更多是简单的介绍。这篇文章不同,因为 erlang 并不是一门新语言,简单介绍它的人不算少,我希望这篇文章能在深度上...

36411
来自专栏机器之心

教程 | TensorFlow 官方解读:如何在多系统和网络拓扑中构建高性能模型

选自Tensorflow 机器之心编译 参与:黄玉胜、黄小天 这个文档和附带的脚本详细介绍了如何构建针对各种系统和网络拓扑的高性能可拓展模型。这个技术在本文档中...

28111
来自专栏张善友的专栏

Ring Buffer 有什么特别?

原文地址: http://mechanitis.blogspot.com/2011/06/dissecting-disruptor-whats-so-speci...

1777

扫描关注云+社区