关于文档型数据库的一点理解

本贴最后更新于 2761 天前,其中的信息可能已经时移世改

最近用 Node+MongoDB 写了一个论坛,期间遇到一些麻烦,也做了一些思考。在此记录一下。

问题

首先表结构是这样的:

User: {
  username: String,
  pass: String
}

Topic: {
  creator: ObjectId,
  tab: String,
  title: String,
  content: String
}

Reply: {
  creator: ObjectId,
  replyId: ObjectId,
  topicId: ObjectId,
  content: String
}

为了便于说明,这里做了一些简化

点开一个帖子,里面应该显示帖子的创建者以及所有回复。这时后台要做的事就很麻烦:

  • 查出帖子
  • 查出帖子的创建者姓名
  • 查帖子的所有回复
  • 查回复的创建者姓名

这里的逻辑写起来非常别扭。为了前台使用的方便,需要把 topic.creator 替换成 user 文档。而根据 mongoose 的设计,查出的数据和数据库里保持一致,如果改变就要 save,否则不能读取改变后的数据。所以这里都要调用 toObject 方法,才能将 topic.creator 替换成 user 文档,这样的话 mongoose 的封装就没有意义了。

再者,前台发出一个请求,后台就要和数据库交流这么多次,这是不合理的。这种拼接对象的逻辑也不是 control 层该干的事。

思考

这个论坛的代码结构很大程度上参考了 nodeclub 这个项目,而这个项目是很久之前的,以现在的角度看,它的设计未必没有问题。MongoDB 进阶模式设计这篇文章给了我很大的启示。

mongoDB 是文档型 nosql 数据库,选择了 mongoDB 就应该改变关系型数据的思维。数据不是一个个的有关系的实体,而是一些互相之间关联较少,内部结构复杂的文档。在 MongoDB 中,应该优先考虑内嵌,比如话题的创建者可以作为一个文档内嵌在话题中。


Topic: {
  creator: {
    _id: ObjectId,
    username: String
  }
  ...
}

这样做就能一次读取需要的信息,大大提高了读取性能,造成的后果是,改变用户名的代价变高了。而改变用户名的机会是比较少的,或者干脆不允许修改用户名问题也不大。所以这样做是比较划算的。

需要注意的是,mongoDB 对单个文档的大小是有限制的:16M。有的时候为了保持可扩展性,就不能使用内嵌。比如将回复看作话题的属性,那回复的内容和数量就会受到这个 16M 的限制,不能无限扩展了。

另外,帖子的回复数量和最后回复时间这样的信息可以从回复表中获取,但也可以看作帖子的一个属性,内嵌在 Topic 表中。这就有一个数据冗余的问题:话题上记录的回复数量和回复表中该话题的回复数量不一致怎么办。有两种办法:一是每次添加或删除回复都去更新 topic 表,二是认为帖子的回复数在一定时间内不会改变太多。比如将这个时间定为三个小时。

Topic: {
  replyCount: {
    timeStamp: Date,
    value: number
  }
  ...
}

读取回复数时,如果数据是三个小时之内的就认为数据是大致准确的,否则从回复表中读取数量。这样其实相当于一个缓存。

  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 29 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    90 引用 • 59 回帖 • 4 关注
  • 论坛
    31 引用 • 280 回帖 • 1 关注

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • jy02201949

    😬原本老是按关系数据库去考虑,难怪这么难搞

  • 其他回帖
  • 88250

    MySQL 加了 JSON 支持后也可以按照内嵌思路来做,不过我还是习惯传统的关联查询,感觉更可控和准确些。

推荐标签 标签

  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 210 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    85 引用 • 139 回帖
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖 • 2 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 478 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 560 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 535 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    110 引用 • 54 回帖 • 1 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    177 引用 • 816 回帖 • 1 关注
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 653 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 160 关注
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 139 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    34 引用 • 148 回帖
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    30 引用 • 96 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    93 引用 • 899 回帖 • 1 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    409 引用 • 1246 回帖 • 587 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 1 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖 • 5 关注
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    692 引用 • 535 回帖
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 50 关注
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 101 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 52 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖 • 1 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 364 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    105 引用 • 127 回帖 • 370 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 653 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    156 引用 • 3792 回帖