MongoDB 数据建模

 

MongoDB 数据建模

一、基本原则:

优先内嵌,其次引用 ---- 主子压缩成1个表

 

1:1、 1:n 强关联聚合(主子) 子数量不是特别多时直接用内嵌文档

m:n 使用reference ,关联表, 更新等要保证事务性

 

二、模型例子

1、电商建模: https://blog.csdn.net/wanght89/article/details/77197400

product和分类

{

   slug:"wheel-barrow-9092",

   sku:"9092",

   name:"Extra Large Wheel Barrow",

   description:"Heavy duty wheel barrow",

   details:{

       weight:47,

       weight_unite:"1bs",

       model_num:40392882,

       manufacturer:"Acme",

       color:"Green"

   },

   total_review:4,

   average_review:4.5,

   pricing:

   {

     retail:589700,

     sale:489700

   },

   price_history:[

   {

   retail:529700,

   sale:429700,

   start:new Date(2010,4,1),

   end:new Date(2010,4,8)

   },

   {

   retail:529700,

   sale:529700,

   start:new Date(2010,4,9),

   end:new Date(2010,4,16)

   }

   ],

   cateory_ids:[

    new ObjectId("59884ee3b53fab2a8024b6ae"),

    new ObjectId("59884ee3b53fab2a8024b6af")

   ],

   main_cate_id:new ObjectId("59884ee3b53fab2a8024b6b1"),

   tags:["tools","gardening","soil"]

}

 

order 订单

{

  _id:new ObjectId("6a5b1476238d3b4dd5000001"),

  user_id:new ObjectId("4a5b1476238d3b4dd5000001"),

  state:"CART",

  line_items:[{

      _id:new ObjectId("4a5b1472134d3b4dd5000921"),

      sku:"9092",

      name:"Extra Large Wheel Barrow",

      quantity:1,

      pricing:{

          retail:5897,

          sale:4897,    

       }

  },

  {

      _id:new ObjectId("4a5b1472134d3b4dd5000922"),

      sku:"10027",

      name:"Rubberized Work Glove,Block",

      quantity:2,

      pricing:{

          retail:1499,

          sale:1299,    

       }

  }

  ],

  shipping_address:{

    street:"588 5th Street",

    city:"Brooklyn",

    state:"NY",

    zip:11215 

  },

  sub_total:6196

}

用户

{

_id:new ObjectId("4a5b1476238d3b4dd5000001"),

email:"kylebanker@gl.com",

first_name:"Kyle",

last_name:"Banker",

hashed_password:"bd1cfa194c3a603e7186780824b04419",

address:[

{ name:"home",

  street:"588 5th Street",

  city:"Brooklyn",

  state:"NY",

  zip:10010

},

{

  name:"work",

  street:"1 E.23rd Street",

  city:"New York",

  state:"NY",

  zip:10010

  

}

],

payment_methods:[{

  name:"VISA",

  last_four:2127,

  crypted:"43f6baldfda6b8106dc7",

  expiration_date:new Date(2014,4)

}

]

}

 

评论

{

 _id:new ObjectId("4c4b1476238d3b4dd5000041"),

 product_id:new ObjectId("59884b76b53fab2a8024b6ad"),

 date:new Date(2010,5,7),

 title:"Amazing",

 text:"Has a squeaky wheel,but still a darn good wheel barrow",

 rating:4,

 user_id:new ObjectId("4a5b1476238d3b4dd5000001"),

 user_name:"dgreenthumb",

 helpful_votes:3,

 voter_ids:[

 new ObjectId("59884b76b53fab2a8024b600"),

 new ObjectId("59884b76b53fab2a8024b601"),

 new ObjectId("59884b76b53fab2a8024b602")

}

}

 

购物车 = items

 

 

2、博客:https://www.qikegu.com/docs/3277

1>user 

2>article= comments+ tags + categorys + user

 

3、社交

关注:   m:n 都比较大时,使用单独的关联表

朋友圈: 每个人存储1份url 使用bucket可以控制数组的大小

iot数据采集:可以采用分桶的方式提高性能(每一个小时的聚合到一个文档里,并做好聚合) 异构的优势

 

4、电影统计

actor

movie = reviews + 。。。

 

 

三、书籍和资料

https://www.lagou.com/lgeduarticle/28746.html

设计模式范式 

https://cloud.tencent.com/developer/article/1405900

 

A Complete Methodology of Data Modeling for MongoDB

Advanced Schema Design Patterns, Daniel Coupal

<MongoDB应用设计模式>

 

四、常见问题,建模范式(访问模式需求,决定架构设计)

 

1、多态 每个document字段都不同,

适合场景:单一视图、内容管理、移动应用、产品目录

 

2、属性模式(Attribute Pattern)-- 把固定的列,变成kv的动态列

 UserDefinedField https://martinfowler.com/bliki/UserDefinedField.html

动态属性子表或者固定的冗余列(分散到每个单据,集中有个配置的地方)

 

问题:部分文档有公共的属性,或者只关注部分属性

电影在多个国家有多个发行日期,怎么查询发行日期?  

方案:统一到1个数组字段,里面obj是kv的结构

 

{

    title: "Star Wars",

    director: "George Lucas",

    ...

    release_US: ISODate("1977-05-20T01:00:00+01:00"),

    release_France: ISODate("1977-10-19T01:00:00+01:00"),

    release_Italy: ISODate("1977-10-20T01:00:00+01:00"),

    release_UK: ISODate("1977-12-27T01:00:00+01:00"),

    ...

}

 

 

{

    title: "Star Wars",

    director: "George Lucas",

    ...

    releases: [

        {

        location: "USA",

        date: ISODate("1977-05-20T01:00:00+01:00")

        },

        {

        location: "France",

        date: ISODate("1977-10-19T01:00:00+01:00")

        },

        {

        location: "Italy",

        date: ISODate("1977-10-20T01:00:00+01:00")

        },

        {

        location: "UK",

        date: ISODate("1977-12-27T01:00:00+01:00")

        },

        ...

    ],

    ...

}

 

索引:{ "releases.location": 1, "releases.date": 1}

 

"specs": [

    { k: "volume", v: "500", u: "ml" },

    { k: "volume", v: "12", u: "ounces" }

]

{"specks.k": 1, "specs.v": 1, "specs.u": 1}

 

3、桶模式  定时分组+预先统计,减少索引带来的内存消耗

 

{

   sensor_id: 12345,

   timestamp: ISODate("2019-01-31T10:00:00.000Z"),

   temperature: 40

}

 

{

   sensor_id: 12345,

   timestamp: ISODate("2019-01-31T10:01:00.000Z"),

   temperature: 40

}

 

{

   sensor_id: 12345,

   timestamp: ISODate("2019-01-31T10:02:00.000Z"),

   temperature: 41

}

 

{

    sensor_id: 12345,

    // 每个小时统计1次

    start_date: ISODate("2019-01-31T10:00:00.000Z"),

    end_date: ISODate("2019-01-31T10:59:59.000Z"),

    measurements: [

       {

       timestamp: ISODate("2019-01-31T10:00:00.000Z"),

       temperature: 40

       },

       {

       timestamp: ISODate("2019-01-31T10:01:00.000Z"),

       temperature: 40

       },

       ...

       {

       timestamp: ISODate("2019-01-31T10:42:00.000Z"),

       temperature: 42

       }

    ],

   transaction_count: 42,

   sum_temperature: 2413

}

 

4、例外模式(Outlier)

问题:突然增长很多数据,比如:影评、书籍畅销榜、社交好友关系

 

添加个 "has_extras": "true",标记是否有非常多的数组元素,有的话去外部关联

 

{

    "_id": ObjectID("507f191e810c19729de860ea"),

    "title": "Harry Potter, the Next Chapter",

    "author": "J.K. Rowling",

    ...,

   "customers_purchased": ["user00", "user01", "user02", ..., "user999"],

   "has_extras": "true"

}

 

 

5、计算模式 Computed Pattern

问题:

总收入、观看人数等聚合运算非常耗费性能,可以在后台计算。

方案:

每个子项目插入或更新时直接计算汇总的结果,同时记录时间戳表示上次更新的时间,适合写少读多

 

例子:iot时序数据、产品分类、大屏应用(single view applications)

 

6、The Subset Pattern 缩减内存使用

内存缓存提高性能,但是内存不足时怎么办? 加内存、做shard分片

场景:商品的评论,电影的演员 (大量非热点数据不应该放入内存) 

方案:把全部存储到product,变成product存储热数据,comment存储历史数据 (需要join一次)

 

7、Extended Reference Pattern

场景:需要join多个表,来表达非热点数据

方案:不是纯粹的外键关联,而是把常用的字段直接关联复制进来

缺点:数据重复

8、近似模式 The Approximation Pattern

场景:不需要非常准确(具有统计意义就可以),但是需要足够快。比如一个城市的常驻人口数量。

方案:不是每行数据都进行更新,每100行,或每一段时间更新一次

 

9、The Tree Pattern 树形结构

关系模型:parent_id 或children(list)

MongoDB:后代同时维护 ancestors:[]和 parent

 

10、 Preallocation Pattern 预分配

使所有数据的数据结构是一致的,哪怕初始的时候是空的,后面再去填充

例子:电影院/酒店的每日订阅情况,4月的工作日有哪些(结构一致会使得算法简单了很多)

 

11、Document Versioning Pattern 文档版本 ---- 添加version字段

不仅是读最新数据,也需要读历史的版本信息。

前提:版本个数不多,需要多版本的文档也不多,大部分还是使用最新版本的数据

适合于强监管的行业,比如金融、医疗、法律、保险

场景:保险主体和附属条款

 

 

current:

{

version:19,

items:[]

}

 

history: 所有的历史版本

{

version:1,

items:[]

},

 

{

version:2,

items:[]

},

 

简单说:每次修改后,生成新版本,把老版本那一行拷贝到历史库。需要使用历史数据时,从历史库里进行查询

 

12、The Schema Versioning Pattern 结构多版本

添加 schema_version 字段,表示新的数据库模式,可以实现不强制升迁数据库的情况下,升级程序。或者同时有多个版本的存储结构

 

customer

{

    "_id": "<ObjectId>",

    "name": "Anakin Skywalker",

    "home": "503-555-0000",

    "work": "503-555-0010"

}

 

{

    "_id": "<ObjectId>",

    "schema_version": "2",

    "name": "Anakin Skywalker (Retired)",

    "contact_method": [

        { "work": "503-555-0210" },

        { "mobile": "503-555-0220" },

        { "twitter": "@anakinskywalker" },

        { "skype": "AlwaysWithYou" }

    ]

}

 

五、其他

 

https://blog.csdn.net/Real_Myth/article/details/51781099

设计模式策略

1、节点读写分离

2、事务

db.queue.insert( { _id : 123,

    message : { },

    locked : false,

    tlocked : ISODate(),

    try : 0 });

var timerange = date.Now() - TIMECONSTANT;

var doc = db.queue.findAndModify( { $or : [ { locked : false }, { locked : true, tlocked : {

$lt : timerange } } ], { $set : { locked : true, tlocked : date.Now(), $inc : { try : 1 } } }

//do some processing

db.queue.update( { _id : 123, try : doc.try }, { } );

 

3、path存储全路径

4、用嵌套避免join

 

 

https://mongoing.com/mongodb-advanced-pattern-design

文档最大16M。一个数组太大会严重影响性能

 

 

方法论:

数据量

场景

模型:做合适的内嵌

设计模式识别

 

 

树形结构:

1、关联 parent 

2、存储children数组

3、关联 parent 和所有祖先

4、带有 编码结构的path

 

 

钱和时间的数据类型 https://docs.mongodb.com/manual/tutorial/model-time-data/

 

 数据模型需要处理的问题:

实现 泛化

关联 1、聚合; 参照 2、组合; 主子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 轨迹数据通常指的是对数据进行分析,以抽象的方式表示数据的特征。常见的方法包括使用统计型,机器学习型等。 轨迹数据的存储常使用数据库存储,以便于数据的查询和分析。常见的存储技术包括关系型数据库(如MySQL),NoSQL数据库(如MongoDB),以及图形数据库(如Neo4j)。 ### 回答2: 轨迹数据与存储是指对移动物体在一段时间内的位置坐标信息进行和存储的过程。具体来说,轨迹数据包括确定可靠的轨迹坐标、地理位置等基本属性,并通过采样频率、采样精度、采样间隔等参数来描述移动物体的运动规律和轨迹形态。而轨迹数据的存储则是将后的数据进行持久化保存,以便后续的数据分析和应用。 在轨迹数据过程中,需要考虑到移动物体的运动特性和采集设备的限制。常见的轨迹数据方法包括离散型和连续型。离散型将轨迹数据分为一系列时间间隔相等的点,每个点包含位置坐标和时间信息,常用的方法有GPS轨迹采集和WiFi基站定位等。而连续型则是通过数学型描述移动物体的运动轨迹,常用的方法有卡尔曼滤波和粒子滤波等。 在轨迹数据的存储过程中,常用的方法包括关系数据库和分布式文件系统。关系数据库适用于较小规的轨迹数据存储,可以通过表结构和索引实现数据的高效查询和管理。而分布式文件系统适用于大规的轨迹数据存储,可以通过分布式存储和并行计算实现对海量数据的存储和处理。 除了基本的和存储方法,还可以通过数据压缩、数据清洗、数据加密等技术来优化轨迹数据和存储过程。总之,轨迹数据与存储对于后续的数据分析和应用具有重要意义,需要结合具体的应用场景和需求来选择合适的和存储方法。 ### 回答3: 轨迹数据与存储是指对于移动物体在一定时间范围内的运行轨迹进行描述和保存的过程。 首先,轨迹数据是指将移动物体的运动过程表示为一条或多条离散的轨迹线段。常用的方法有点型和线段型。点型将物体在不同时间点的位置坐标作为点,用坐标对表示。线段型将物体在相邻时间段内的运动轨迹表示为线段,用线段的起始点和终止点坐标进行表示。 其次,轨迹数据的存储是指将后的轨迹数据保存在计算机中,以便后续的分析和应用。常用的存储方式有两种:数据库存储和文件存储。数据库存储使用数据库管理系统,将轨迹数据以表的形式存储,每个表的记录表示一个时间点的轨迹点或一段时间内的轨迹线段。文件存储是将轨迹数据保存为一个或多个文件,每个文件表示一个完整的轨迹,包含各个时间点的位置坐标信息。 在轨迹数据的存储过程中,还需要考虑数据的压缩和索引。数据压缩可以减小存储空间,提高数据的读写效率,常用的压缩方法有编码压缩和差值压缩。数据索引是为了提高轨迹数据的检索性能,常用的索引方式有R树索引和哈希索引。 最后,轨迹数据与存储是移动物体追踪、路径规划、空间分析等应用的基础,它可以帮助我们理解和分析物体的运动行为,从而为交通管理、物流配送、城市规划等领域提供决策支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值