MongoDB 学习笔记 - Data Models


Data Model概念

如果要给MongoDB打标签,那么首选的几个标签无非是NoSQL, 非关系型数据库, 分布式文档存储数据库。而关系型数据库,非关系型数据库一个非常重要的区别就是Data Model。Data Model 决定了“要怎么存”,“适用怎么查”等,也是选型的一个重要考虑因素。

所以呐,我们不能用MySQL那一套建表的惯性来思考。MongoDB的Data Model主要有两类,Embedded Data Models和Normalized Data Models。

Embedded Data Models

嵌入式数据模型,顾名思义,我们把子文档嵌入在主文档里面。如下图,主文档是用户属性,而用户的联系方式,操作权限级别等子属性,一并用嵌入的方式,放进我们的用户属性文档里面。

这种数据模型可以很好的应用于“一对一”,“一对多”的关系结构上,例如上面的用户联系方式就是“一对一”,用户操作权限级别就是“一对多”(一个用户只有一个操作级别,一个操作级别对应很多用户)。

?? 优势:??MongoDB本身是推荐使用这样的数据模型的。其一,因为这种结构对于“读”场景来说,只用做一次读操作,不用去查很多表;其二,MongoDB对单文档操作时原子性的,所以天生对于一个文档的不同field的更新操作是安全的。
?? 缺点:数据冗余,以及数据冗余带来的性能问题等;“多对多”的关系比较难以表达。

Normalized Data Model

标准化数据模型,就和之前学过的关系型数据库很像了,它使用references来关联两个文档。

标准化数据模型主要就是针对嵌入式数据模型的两个缺点来补充的。而对于标准化数据模型查询时,避免不了的join操作,MongoDB提供了$lookup,$graphLookup来提供。但是我们在使用MongoDB的时候,仍然需要优先考虑嵌入式数据模型。如果必须存在很多join操作,那需要考虑是不是不要使用MongoDB了。

设计Data Model

官方讲座

数据模型的应用场景

这里列举一些官方展示的应用场景的考虑:

原子操作

如果有些field需要作为一个原子操作一起更新,就需要考虑把它们放在一个文档里面。例如图书馆里书籍信息里面的可用数量和借书信息需要一起更新:

{
    _id: 123456789,
    title: "MongoDB: The Definitive Guide",
    author: [ "Kristina Chodorow", "Mike Dirolf" ],
    published_date: ISODate("2010-09-24"),
    pages: 216,
    language: "English",
    publisher_id: "oreilly",
    available: 3,
    checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]
}

就可以:

db.books.updateOne (
   { _id: 123456789, available: { $gt: 0 } },
   {
     $inc: { available: -1 },
     $push: { checkout: { by: "abc", date: new Date() } }
   }
)

关键字搜索

这里的关键字搜索和全文搜索是不一样的。MongoDB可以创建multi-key index。图书管理书籍信息如下:

{ title : "Moby-Dick" ,
  author : "Herman Melville" ,
  published : 1851 ,
  ISBN : 0451526996 ,
  topics : [ "whaling" , "allegory" , "revenge" , "American" ,
    "novel" , "nautical" , "voyage" , "Cape Cod" ]
}

可以在topics数组上创建multi-key index

db.volumes.createIndex( { topics: 1 } )

查询就可以根据关键字查,如:

db.volumes.findOne( { topics : "voyage" }, { title: 1 } )

其他

例如针对金融数据,IoT数据等等