MongoDB实战读书笔记(二):面向文档的数据
1 schema设计原则
1.1 关系型数据库的三大设计范式
- 第一范式(1NF)无重复的列
- 第二范式(2NF)属性完全依赖于主键 [ 消除部分子函数依赖 ]
- 第三范式(3NF)属性不依赖于其它非主属性 [ 消除传递依赖 ]
参考:https://blog.csdn.net/zhangminemail/article/details/56834253
1.2 选择Mongodb需要考虑
- 读写比例、查询语句是否复杂、是否需要聚合函数、数据量
- 数据基本单位是什么
- RDBMS:表
- 键值数据库:键指向的值
- Mongodb:BSON文档
- 是否需要强事务支持
- 如何记录生成好的唯一ID或者主键,如:RDMS支持联合主键
1.3 schema基础
(1)文档设计
// 商品
{
_id: ObjectId("4c4b1476238d3b4dd5003981"), // 唯一ID
slug:"wheelbarrow-9092", // 唯一slug
sku:"9092",
name:"Extra Large wheelbarrow",
description:"Heav y duty wheelbarrow...",
details:{ // 嵌套文档
weight:47,
wight_units:"lbs",
model_num: 4039283402,
manufacturer:"Acme",
color:"green"
},
total_reviews: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)
}],
primary_category: ObjectId("6a5b1476238d3b4dd5000048"), // 一对多
category_ids:[ // 多对多
ObjectId("6a5b1476238d3b4dd5000048"),
ObjectId("6a5b1476238d3b4dd5000049")
],
main_cat_id: ObjectId("6a5b1476238d3b4dd5000048"),
tags:["tools","gardening","soil"]
}
(2)唯一slug
// http://domain.com/products/4c4b1476238d3b4dd5003981
// 展示相对友好一些
// http://domain.com/products/wheelbarrow-9092
db.products.createIndex({slug:1},{unique:true});
(3)内嵌文档
一般用于需要动态修改的内容
如:details为商品详情,每个商品包含的信息不一样。如果是U盘,还需要标识内存大小;如果是桌子,需要标识高度等。
(4)一对多
一个商品只对应一个主要类别,一个类别下有多个商品
(5)多对多
一个商品对应多个关联类别,一个类别有多个商品
(6)关系结构
类别文档可以复用,所以我们需要把它提取出来,而不是像商品信息那样直接嵌套在商品中。
// 类别文档 Home -> Outdoors -> Gardening Tools
{
_id: ObjectId("6a5b1476238d3b4dd5000048"), // Outdoors的子类别
slug:"gardening-tools",
name:"Gardening Tools",
description:"Gardening gadgets glore!",
parent_id: ObjectId("55804822812cb336b78728f9"),
// 冗余数据,用于快速查找
ancestors:[{
name:"Home", // 商品类别
_id:ObjectId("55804822812cb336b78728fa"),
slug:"home"
},{
name:"Outdoors", // Home的子类别
_id:ObjectId("55804822812cb336b78728f9"),
slug:"outdoors"
}]
}
(7)查询
// 查询该类别的所有商品
db.products.find({category_ids:ObjectId("6a5b1476238d3b4dd5000048")})
// 查询商品的所有类别信息
db.categories.find({_id:{$in:product['category_ids']}})
db.products.findOne({'slug':'wheelbarrow-9092'})
1.4 用户和订单:一个用户多个订单
(1)订单
// 订单
{
_id:ObjectId("6a5b1476238d3b4dd5000118"),
user_id:ObjectId("4c4b1476238d3b4dd5003981"), // 用户ID
state:"CART",
line_items:[{
_id:ObjectId("4c4b1476238d3b4dd5003981"),
sku:"9092",
name:"Extra Large Wheelbarrow",
quantity:1,
pricing:{
retail:5897,
sale:4897
}
},{
_id:ObjectId("4c4b1476238d3b4dd5003982"),
sku:"10027",
name:"Rubberized Work Glove, Black",
quantity:2,
pricing:{
retail:1499,
sale:1299
}
}],
shipping_address:{
street:"588 5th",
city:"Brooklyn",
state:"NY",
zip:11215
},
sub_total:6196
}
(2)用户
{
_id:ObjectId("4c4b1476238f3b4dd5000042"),
username:"test",
email:"test@test.com",
first_name:"Kyle",
last_name:"Banker",
hashed_password:"bd1cfa194c3a603e7186780824b04419",
addresses:[{
name:"home",
street:"588 5th",
city:"Brooklyn",
state:"NY",
zip:11215
},{
name:"word",
street:"1 E. 23th",
city:"New York",
state:"NY",
zip:10010
}],
payment_methods:[{
name:"VISA",
payment_token:"43f6ba6b8106fc7"
}]
}
(3)查询操作
// 查询用户的所有订单
db.orders.find({user_id:user['_id']})
// 查询订单的用户信息
db.users.findOne({_id:orders['user_id']})
1.5 评价
{
_id: ObjectId("4c4b1476238d3b4dd5000041"),
product_id: ObjectId("4c4b1476238d3b4dd5003981"),
date: new Date(2010,5,7),
title:'Amazing',
text:'Amzing.I love it.',
rating:4,
user_id: ObjectId("4c4b1476238f3b4dd5000042"),
username: "dgreethumb",
helpful_votes:3,
voter_ids:[ // 评论者的用户ID,阻止多次投票
ObjectId("4c4b1476238f3b4dd5000133"),
ObjectId("4c4b1476238f3b4dd5000003"),
ObjectId("4c4b1476238f3b4dd5001032")
]
}
2 核心概念:数据库、集合、文档
2.1 数据库
(1)数据库是集合和索引的命名空间和物理分组
(2)管理数据库
// 使用garden数据库
> use garden
// 删除当前数据库
> db.dropDatabase()
// 数据库当前状态
> db.stats()
{
"db": "garden",
"collections": NumberInt("4"),
"views": NumberInt("0"),
"objects": NumberInt("477985"),
"avgObjSize": 178.613015052774,
"dataSize": 85374342, // 数据库实际BSON大小
"storageSize": 30539776,// 额外的为集合增长预留的空间
"numExtents": NumberInt("0"),
"indexes": NumberInt("9"),
"indexSize": 10194944, // 索引总大小
"ok": 1
}
2.2 集合
(1)集合是结构或概念上相似的文档的容器。
(2)管理集合
// 显式创建集合
db.createCollection("users");
// 显式创建集合并指定分配空间的大小(字节)
db.createCollection("users",{size:20000});
// 集合名不能超过128个字符
// 重命名集合
db.products.renameCollection("store_products");
(3)固定集合
- 指定集合的大小和集合的容量,类似一个队列,满了之后新的数据进来,最久的数据出去
// Max size:16384kB 数量:100
> db.createCollection("users.actions",{capped:true,size:16384,max:100})
(4)TTL集合
- MongoDb允许在特定的时间后废弃文档数据。
// 一分钟失效,依赖索引机制
> db.reviews.createIndex({time_field:1},{expireAfterSeconds:3600})
(5)系统集合
> db.system.users.find()
> db.system.version.find()
2.3 文档
(1)类型
- 字符串:UTF-8编码,不能由$开始,不包含圆点、不能包含null字节
- 数字:double、int、long
- 时间:从Unix纪元计时开始时间值使用64b整数的毫秒表示
- 虚拟类型:
// 配合应用程序的converter进行转换
// 参考:https://www.cnblogs.com/linzhanfly/p/9578738.html
{
time_with_zone:{
time:new Date(),
zone:"EST"
}
}
(2)限制
-
BSON文档大小限制为16MB
-
文档嵌套深度最大为100
-
插入操作上限为16MB,即如果插入100W条数据需要分割为多个大量插入的文档组。