MongoDB小课堂: 数据模型设计从基础到实战——文档结构、关系表达与树形建模深度指南

【信息科学与工程学】【数据中心】第三十五篇 云计算数据中心的学科知识04 编号学科(课程)核心知识点在云计算/云存储/云网络/云安全/云MaaS中的作用代表教材/资料/论文 + 数学方程式列表工业界应用D1421​云原生数据库:TiDB​HTAP(混合事务/分析处理)、分布式SQL、水平扩展、强一致(Raft)、自动故障恢复、与MySQL兼容、TiFlash列式引擎提供弹性扩展的分布式数据库;支撑高并发在线交易与实时分析教材:《TiDB in Action》PingCAP(2020) 论文:《TiDB: A Raft-based HTAP Database》(2017) 阅读详情

背景

  • MongoDB作为领先的文档型数据库,其灵活的数据模型支持复杂业务场景,但设计不当会导致性能瓶颈
  • 现在我们系统解析文档结构设计原则、关系表达策略(一对一、一对多)及树形建模高级技巧
  • 基于实际工程实践,聚焦高频读写模式、数据一致性、扩展性控制等关键挑战,帮助开发者构建高性能MongoDB架构

文档结构与关系表达基础


MongoDB通过两种核心结构管理数据关系,需根据读写频率和数据独立性选择:

1 ) 内嵌式结构 (Embedded Documents)

  • 定义:将关联数据直接嵌套在父文档中(如联系方式内嵌至银行账户)。
  • 代码示例:
    {
      _id: ObjectId("5f8d8a7b2f4c2e1288d48a21"),
      accountHolder: "Alice",
      currency: "CNY",
      contact: {  // 内嵌子文档
        phone: "+86-13800138000",
        email: "alice@example.com"
      }
    }
    
  • 优势:单次查询获取完整数据,减少I/O开销(读取性能 ⭐⭐⭐⭐)。
  • 适用场景:高频读取、低频更新的补充性数据(如账户开户信息)。

2 ) 规范式结构 (Normalized References)

  • 定义:通过文档主键(_id)引用独立文档(类似外键)。
  • 代码示例:
    // 独立联系方式文档
    { _id: ObjectId("5f8d8a7b2f4c2e1288d48c42"), phone: "+86-13800138000", email: "alice@example.com" }
    
    // 银行账户文档(引用contactId)
    {
      _id: ObjectId("5f8d8a7b2f4c2e1288d48a21"),
      accountHolder: "Alice",
      contactId: ObjectId("5f8d8a7b2f4c2e1288d48c42")  // 引用关联
    }
    
  • 优势:避免冗余,更新仅需修改单文档(更新复杂度 ⭐⭐⭐⭐)
  • 适用场景:数据独立性高、高频更新(如共享联系方式)

决策矩阵:

维度内嵌式规范式趋势建议
读取性能⭐⭐⭐⭐ (单次查询)⭐⭐ (需多次查询)读多场景优选内嵌
更新效率⭐ (可能需多文档更新)⭐⭐⭐⭐ (单点更新)写多场景优选规范式
数据一致性需事务保证⭐⭐⭐ (天然一致)关键操作强制启用事务
扩展性文档可能膨胀(>16MB风险)⭐⭐⭐⭐ (稳定尺寸)数组元素>100时转用引用

要点

  • 术语简注:内嵌式(数据嵌套)、规范式(ID引用)
  • 核心原则:读多内嵌、写多引用,单文档不超过16MB

关系表达实战策略


根据关系复杂度(一对一、一对多)选择模型,结合访问模式优化

1 ) 一对一关系建模

  • 场景示例:银行账户与开户信息。
  • 设计原则:主实体作为外层文档,补充属性内嵌。
  • 代码示例:
    {
      _id: ObjectId("5f8d8a7b2f4c2e1288d48a21"),
      accountNumber: "6230520088887777",
      accountOpening: {  // 内嵌开户信息
        openDate: ISODate("2023-01-15"),
        branch: "Beijing CBD Branch"
      }
    }
    

设计原则:

  1. 主实体作为外层文档(如银行账户)
  2. 补充属性作为内嵌文档(如开户信息)
  3. 优先考虑数据访问模式而非理论规范

2 ) 一对多关系建模

方案1:内嵌数组

  • 适用:子项数量少(<100)、读多写少。

  • 风险:文档膨胀影响性能。

  • 示例:

     {
          _id: ObjectId("5f8d8a7b2f4c2e1288d48b33"),
          name: "Alice",
          customerId: "CUST_ALICE",
          accounts: [  // 内嵌账户数组
            { accountId: "ACC001", type: "SAVINGS" },
            { accountId: "ACC002", type: "CHECKING" }
          ]
    }
    
    • 适用场景:子文档数量有限(建议 < 100)且读多写少

方案2:引用式数组

  • 适用:子项数量大(>100)或需独立更新。
  • 优势:支持$lookup聚合查询。
  • 示例(含聚合查询):
    // 客户文档存储引用ID
    {
      _id: ObjectId("5f8d8a7b2f4c2e1288d48b33"),
      accountIds: [ObjectId("ACC001"), ObjectId("ACC002")]
    }
    
    // 聚合查询关联账户 
    db.customers.aggregate([
      { $match: { _id: ObjectId("5f8d8a7b2f4c2e1288d48b33") } },
      { $lookup: {
          from: "accounts",
          localField: "accountIds",
          foreignField: "_id",
          as: "linkedAccounts"
      }}
    ])
    

优势:

  1. 避免文档膨胀($lookup 聚合实现关联查询)
  2. 支持大规模子项(>1000)
    // MongoDB聚合查询示例 
    db.customers.aggregate([
      { $match: { name: "Alice" } },
      { $lookup: {
          from: "accounts",
          localField: "accountIds",
          foreignField: "_id",
          as: "linkedAccounts"
      }}
    ])
    

要点

  • 关键决策:子项数量是核心因素(<100内嵌,>100引用)
  • 性能提示:为引用字段(如accountIds)建索引加速查询

树形结构高级建模


针对层级数据(如分类体系),五种方案按查询需求选择:

1 ) 父引用模式

  • 结构:节点存储父ID。
  • 适用:查询直接子节点。
  • 示例:
    { _id: "MongoDB", parentId: "DocumentDB" }
    

2 ) 子引用模式

  • 结构:父节点存储子ID数组。
  • 适用:快速定位父节点。
  • 示例:
    { _id: "NoSQL", children: ["DocumentDB", "KeyValueDB"] }
    

3 ) 祖先路径模式

  • 结构:存储完整祖先链。
  • 适用:子树查询(如找所有NoSQL子类)。
  • 示例:
    { 
      _id: "MongoDB", 
      ancestors: ["Databases", "NoSQL", "DocumentDB"] 
    }
    

4 ) 物化路径模式

  • 结构:路径字符串 + 深度。
  • 适用:正则匹配子树。
  • 示例:
    { 
      _id: "MongoDB", 
      path: "Databases/NoSQL/DocumentDB", 
      depth: 3 
    }
    

5 ) 左右值编码(嵌套集合)

  • 结构:left/right编号标记位置

  • 适用:静态数据的高效子树查询

  • 示例:

    { _id: "NoSQL", left: 6, right: 13 }
    { _id: "MongoDB", left: 10, right: 11 }
    
  • 查询子树:

    SELECT * FROM categories 
    WHERE left > 6 AND right < 13; /* SQL类比 */
    

优势:

    1. 单次查询获取完整子树
    1. 快速判断节点层级关系

方案对比图表(mermaid格式):

树形操作需求
获取父链
获取子树
频繁更新
父引用/祖先路径
左右值编码
父引用

执行效率对比:

获取父链
获取子树
频繁更新
查询需求
树形操作类型
父引用/祖先路径
左右值编码
父引用

要点

  • 静态 vs 动态数据:左右值编码适合静态树(更新成本高),父引用适合动态数据
  • 索引优化:为parentId、ancestors、left/right建索引

实际应用场景与代码实现


场景:电商平台用户-订单系统

  • 需求:用户(一对多订单),订单内嵌商品详情(低频更新)。
  • 模型设计:
    // 用户文档(引用订单ID)
    {
      _id: "USER_001",
      name: "Alice",
      orderIds: ["ORDER_1001", "ORDER_1002"]  // 一对多引用
    }
    
    // 订单文档(内嵌商品详情)
    {
      _id: "ORDER_1001",
      userId: "USER_001",
      items: [  // 内嵌数组(商品数<50)
        { productId: "P123", quantity: 2, price: 299 },
        { productId: "P456", quantity: 1, price: 599 }
      ]
    }
    

事务保障示例:

import { ClientSession } from 'mongodb';
 
async function updateUserOrder(userId: string, newPhone: string) {
  const session = await mongoose.startSession();
  session.startTransaction();
  try {
    // 更新用户联系方式
    await UserModel.updateOne(
      { _id: userId },
      { $set: { phone: newPhone } },
      { session }
    );
    
    // 更新关联订单状态
    await OrderModel.updateMany(
      { userId: userId },
      { $set: { "contactVerified": false } },
      { session }
    );
    
    await session.commitTransaction();
  } catch (error) {
    await session.abortTransaction();
    throw error;
  }
}

关键挑战:跨文档更新需事务(MongoDB 4.0+支持),超时默认60秒。

SQL对比示例

-- 规范式结构的SQL等效实现
CREATE TABLE contacts (
 id VARCHAR(20) PRIMARY KEY,
 phone VARCHAR(15),
 email VARCHAR(50)
);

CREATE TABLE accounts (
 id VARCHAR(20) PRIMARY KEY,
 owner VARCHAR(50),
 contact_id VARCHAR(20) REFERENCES contacts(id)
);

-- 查询账户及联系方式
SELECT a.*, c.phone, c.email 
FROM accounts a
JOIN contacts c ON a.contact_id = c.id;

结论

注意事项

  • 内嵌式:优先用于高频查询、数据独立性强的场景(如账户详情)
  • 规范式:适合数据共享、高频更新的场景(如客户联系方式)
  • 树形结构:
    • 父/子指针:简单层级查询
    • 祖先数组/嵌套集合:深层级子树分析(需权衡更新成本)
  • 核心原则:基于应用访问模式设计模型,而非强制套用范式

核心设计原则与优化建议

1 ) 读写模式驱动设计

  • 高频读取:内嵌式(如账户详情)。
  • 高频更新:规范式(如共享联系方式)。
  • 案例验证:电商订单系统实测显示,内嵌商品详情减少查询延迟40%。

2 ) 数据生命周期管理

  • 树形结构:静态数据用祖先路径/左右值编码,动态数据用父引用。
  • 扩展控制:数组字段元素超100时拆分为独立集合。

3 ) 事务与一致性

  • 启用多文档事务保障关键操作(参考NestJS示例)。
  • 补充限制:MongoDB 6.0+优化了跨分片事务性能,支持更复杂场景。

4 ) 性能优化强制措施

  • 索引策略:为所有查询字段(如parentId、accountIds)建索引。
  • 文档监控:Alert机制检测文档大小逼近16MB。

补充细节:

  • 最新特性:MongoDB 7.0引入时序集合优化树形数据更新
  • 案例扩展:添加金融系统账户树案例(使用左右值编码处理静态分类)
  • 性能数据:内嵌 vs 引用在10K文档下的吞吐量对比(内嵌读速高30%,但写速低50%)

最终结论:数据模型设计是业务场景与技术特性的平衡艺术。遵循“访问模式优先”原则,结合事务与索引,才能释放MongoDB的灵活性与性能潜力

MongoDB树状数据存储技巧:第2部分 在讨论单一文档表示法(Single Document Schema)之前,我们需要了解其底层的数据模型。单一文档表示法是将相关联的数据存储在单一的MongoDB文档中。这种模型借鉴了文档数据库的灵活性,允许开发者将对象的所有相关数据一起存储,减少或避免了传统数据库中的外键和连接操作。这意味着开发者可以实现快速的读取操作,并且数据结构的变更相对简单,因为它不要求变更表结构或者进行复杂的迁移。引用关系存储是一种在文档之间建立关联的数据存储策略,它可以用来模拟实体之间的关系。 阅读详情

相关推荐

使用MongoDB存储类似层次结构的树

在MongoDB中使用NoSQL数据库存储树状结构的三种方法

MongoDB树形数据存储

MongoDB树形数据存储

u012632105的博客 969

WebRTC音频传输实战:从采集到播放的完整链路解析(附RTP包处理细节)

本文深入解析了WebRTC音频传输的完整链路,从麦克风采集、音频处理与编码,到RTP打包、网络发送,再到接收端的NetEQ抗抖动处理与最终播放。文章以Linux PulseAudio为例,详细剖析了线程模型、缓冲区管理及RTP包处理等关键细节,旨在帮助开发者优化实时音频应用的延迟、卡顿与回声问题。

tea88的博客 853

MongoDB五种树形结构表示法

MongoDB五种树形结构表示法 MongoDB五种树形结构表示法 第一种:父链接结构 db.categories.insert( { _id: "MongoDB", parent: "Databases" } ) db.categories.insert( { _id: "dbm", parent: "Databases" } ) db.categori...

diaowojian9497的博客 1009

使用Hyper-V使用下载下来的macOS安装引导安装macos

然后关闭工具返回安装界面选择第二个reinstall,选择119g那个硬盘。我的资源上传了:macOS Monterey on Hyper-V.7z。设置固件的启动顺序,引导安装盘放到第一位,mac安装110g放第二。选择disk utility格式化那个110g。下载解压的macos引导挂载到虚拟硬盘。其他设置安全禁用,检查禁用,集成都选中。新建一个虚拟硬盘装mac,110g。

viviliving的专栏 3026

AD在建PCB封装时如何添加元器件的3D模型

3D模型

k1ang的博客 1万+

Mongodb 数据存储是 B+ TREE 还是 B TREE

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(接近700人左右 1 + 2)。前一段被问及MOGNODB 到底是 B+TREE 还是 B TREE ,这个问题根据之前的记忆是 BTREE ,而...

sql server的专栏 457

rk3588s-摄像头适配gc8034

若还打开失败,需要看下XML中文件配置是否与DTS配置信息一致,或者XML参数配置是否有异常;MIPI摄像头是有上电时序要求,具体时序要查看sensor芯片对应的datasheet进行修改,如果时序不满足,sensor无法正常,此时用i2ctool去查看设备可能无法扫面到设备,即是i2c设备找不到。RK3588或者RK3588S有路MIPI-PHY,驱动开发工程师需要根据对应的硬件原图进行配置,以下会讲解分别使用MIPI-DPHY和MIPI-D/CPHY如何在DTS配置mipi摄像头的回环链路。

Yxx8066的博客 2201

mongodb树形结构

    在mongodb中有多种方式来存储属性结构的数据。     1 通过子文档关联父文档 { "_id": 1, "name": "子节点", "parents": ["父节点1","父节点2"] }     2 通过父节点关联子节点 { "_id": 1, "name": "父节点",

hello world 5016

Simulink封装与库的建立

第二栏设置标签,第三栏是对应变量名,即是第一张图中的常量名。1.先将输入与常量模块相连接并生成子系统。按照如图所示添加修改,最后的效果如下图。封装子系统搭建测试环境。

lensyu1994的博客 1743

面向干净核心的并行扩展:SAP BTP 上的 side-by-side extensions 全面解读

摘要: SAP的side-by-side extensions是一种与核心系统解耦的云原生扩展模式,通过API和事件驱动实现与SAP S/4HANA等核心系统的松耦合集成。该模式支持独立升级、弹性扩展和高效创新,是SAP官方推荐的clean core关键实现路径。其典型架构包括接口层(OData/REST API、事件通道)、运行层(Cloud Foundry/Kyma/CAP框架)和体验层(Fiori/UI5)。适用场景包括需快速迭代、复用云服务或服务外部用户的业务扩展。实施时需关注安全治理(如XSUAA

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 306

HKUST Spark 大数据笔记(一)

大数据”并没有一个单一的标准定义。例如,维基百科的定义是:任何因其规模、复杂性和速度而需要新的架构、技术、算法和分析来管理并从中提取价值和隐藏知识的数据集。然而,这个定义并不完美,因为它将“大数据”变成了一个不断移动的目标——一旦我们开发出新的技术来处理它,它就不再是“大数据”了。尽管如此,这个定义确实揭示了大数据的某些特征。业界普遍认同大数据的“3V”特性,即体量多样性和速度。本节课中我们一起学习了大数据的基本概念。总结来说,“3V”特性(体量、多样性、速度)是大数据的核心。

龙哥盟 192

玩转Docker小游戏项目系列:Docker部署魔塔网页经典小游戏

玩转Docker小游戏项目系列:Docker部署魔塔网页经典小游戏

jks212454的博客 1063

MongoDB 数据建模从入门到精通:核心思想、实操步骤与最佳实践

以查询为导向:高频查询优先,所有设计为 “减少查询延迟” 服务;优先嵌入,合理引用:能嵌入的不引用,避免频繁$lookup;控制文档大小:避免单文档超过 16MB,用子集 / 引用拆分大数据;索引精简化:只为高频查询创建索引,定期清理无用索引;灵活迭代:业务变化后,通过重新分析工作负载,调整模型。

佑瞻的博客 1244

YOLOv12涨点改进 | 全网首发,Conv改进篇 | CVPR 2025 | YOLOv12引入FDConv频率动态卷积,含A2C2f_FDConv二次创新模块,能够捕捉更加丰富和复杂的特征信息

本文提出了一种改进YOLOv12目标检测模型的方法——频率动态卷积(FDConv)。FDConv通过增强卷积核的频率响应多样性,使模型能够更好地处理不同频率信息,从而提高检测精度。该方法包含三个关键组件:傅里叶离散权重(FDW)实现频率分组,核空间调制(KSM)动态调整频率响应,以及频率带调制(FBM)进行频域调节。实验结果表明,FDConv能以较少的参数增长(仅增加3.6M)显著提升模型性能,在目标检测、实例分割等任务中优于传统动态卷积方法。该方法可灵活集成到ResNet、ConvNeXt等多种架构中。

Ai缝合怪、助力小伙伴高效发论文 421

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

mongodb数据模型设计

内嵌是monodb建模的主要手段!一般建议的是先考虑内嵌, 直接按照你的对象模型来设计你的数据模型。如果你的对象模型数量不多,关系不是很复杂,那么恭喜你,可能直接一种对象对应一个集合就可以了。

西京刀客 4188

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

[ mongoDB ] - 文档型数据库设计模式-如何存储树形数据 [转]

在数据库中存储树形结构的数据,这是一个非常普遍的需求,典型的比如论坛系统的版块关系。在传统的关系型数据库中,就已经产生了各种解决方案。 此文以存储树形结构数据为需求,分别描述了利用关系型数据库和文档型数据库作为存储的几种设计模式。 A.关系型数据库设计模式1 id name parent_id 1 A NULL 2 B 1 3 C 1...

weixin_34258782的博客 798

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Mac下MySQL的配置和修改密码以及忘记密码后的重置密码

1 ) Mac下MySQL的配置和修改密码 2 ) 忘记并重置密码 启动MySQL服务,通过 $ps aux | grep mysql 判断是否启动该服务,若未启动,则到 系统偏好设置/MySQL面板 启动服务 软件默认会安装到:/usr/local/mysql 目录,进入这个目录下的bin目录:$cd /usr/local/mysql/bin 执行 $./mysql -u root -p 通过初始密码登录MySQL 通...

Wang的专栏 6259

mysql数据库的一些简单的sql语句 内连接 - 表的关联查询

# 创建一个user表 create table users( id int primary key auto_increment, name varchar(20), dpt_id int ); # 向user表中插入数据 insert into users values (null,'刘备',1), (null,'关羽',2), (null,'赵

Wang的专栏 4264

数据库、数据库类型、RDBMS以及MySQL

什么是数据库 数据库 就是按一定的结构来组织、存储和管理数据的仓库 可以很方便的进行crud, 能提供多个用户共享、具有尽可能小的冗余度、与应用程序批次独立的数据集合。 其他持久储存缺点:文件操作(不灵活) 数据库类型 包括 : 关系型 和 非关系型 【关系型】 MySQL MariaDB PostgreSQL Microsoft SQL Server Oracle数据库 Sybase 【...

Wang的专栏 4039

Eggjs笔记:Eggjs集成ElasticSearch及CRUD操作

相关文档 https://www.elastic.co/guide/index.html https://www.elastic.co/guide/en/elasticsearch/client https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/configuration.html https://www.elastic.co/guide/en/elasticsearch/client/javascrip

Wang的专栏 3530

Redis: 集群高可用之故障转移和集群迁移

若要检查源和目标是否数据统一,还可选择阿里配套工具RedisFullCheck。3.4 使用 RedisFullCheck 工具检查。下载官方编译好的工具包,直接解压后就能使用。故障转移,包括自动故障转移和手动故障转移。运行之后,就给一个反馈结果,如果是。1.2 原集群与目标集群结构不一致。1.1 原集群与目标集群结构一致。2 ) 手动故障转移。

Wang的专栏 2918

Python笔记:基于Django框架的数据库设计

概述 需要根据《项目建议书》、《需求说明书》、界面原型、各种标准规范对数据库进行设计, 我们目前先参考这一设计图 结构设计 1 ) 找实体 实体是实体-关系模型的基本对象, 是现实世界中各种事物的抽象。 凡是可以相互区 开并可以被识 的事、物、概念等对象均可认为是实体。 基本的实体列表如下: 会员 类别 商品 订单 订单详情 收货地址 商品评论 商品图片 友情链接 站内公告 … ...

Wang的专栏 2772
上一篇: MongoDB小课堂: 构建高可用股票仓位管理API服务(Express+Mongoose全栈实战)
下一篇: MongoDB小课堂: 聚合管道实战详解与性能优化策略
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值