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

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

最近用 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 模型而得以轻量和高效。

    138 引用 • 268 回帖 • 147 关注
  • MongoDB

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

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

相关帖子

欢迎来到这里!

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

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

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

  • jy02201949

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

推荐标签 标签

  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 52 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 247 回帖 • 148 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    493 引用 • 1385 回帖 • 342 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 405 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 531 关注
  • Android

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

    334 引用 • 323 回帖 • 25 关注
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 683 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 232 回帖
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    124 引用 • 580 回帖
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 614 关注
  • Electron

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

    15 引用 • 136 回帖 • 5 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 1 关注
  • 安装

    你若安好,便是晴天。

    131 引用 • 1184 回帖 • 1 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 21 关注
  • Sandbox

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

    379 引用 • 1221 回帖 • 588 关注
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 1 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 50 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 31 回帖 • 8 关注
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    541 引用 • 3529 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 611 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 383 回帖 • 4 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    324 引用 • 1395 回帖 • 4 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    21 引用 • 37 回帖 • 519 关注
  • 分享

    有什么新发现就分享给大家吧!

    244 引用 • 1762 回帖
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    11 引用 • 5 回帖 • 582 关注