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条数据需要分割为多个大量插入的文档组。

原文地址:https://www.cnblogs.com/linzhanfly/p/9719320.html