MongoDB本身不强制使用schema,但是我们在做一个服务应用的时候,应该要知道数据应该怎么组织。
MongoDB设计的考虑
MongoDB的数据库与关系型数据库一样,也存在一对多、多对多等关系。关系型数据库设计的时候有数据库设计范式(1NF,2NF,3NF,BCNF等等),非关系型数据库要思考的问题则不太一样:
- 关系型数据库的数据基本单位是行和列,MongoDB的数据基本单位是BSON文档;
- 关系型数据库一般只吃ad hoc即席查询以及连接;MongoDB支持ad hoc,但不支持连接;
- 关系型数据库允许使用SQL进行复杂的更新,可以在事务中包含多个更新并支持原子性和回滚;MongoDB不支持事务,但支持更新复杂结构的文档数据;
- MongoDB无需指定id生成策略,会自动生成_id;
- MongoDB无法与Hibernate之类的ORM框架结合使用;因为文档本身已经是类对象的表示形式了。
MongoDB相关概念
数据库
数据库是集合和索引的命名空间和物理分组。
MongoDB没有显式地创建数据库的方式,而是会在第一次写入数据的时候创建数据库。
创建数据库的时候,MongoDB会在磁盘上分配一系列数据库文件集合,包括所有的集合、索引,以及其他元数据。
数据库文件存储在mongod启动时的dbpath参数指定的目录文件夹中;如果不指定dbpath,则会默认在/data/db文件夹下存储。
.ns文件用来表明命名空间;数据库中每个集合和索引的元数据都有自己的命名空间文件,组织形式是哈希表。.ns文件固定大小16MB,意味着数据库中集合和索引的数目之和不能超过26000。
MongoDB还为集合和索引在文件里分配空间,从0开始以递增的方式作为后缀。
db.status()可以查看数据库的各项信息,如空间信息等:
fileSize表示数据库的所有文件的大小;
dataSize是数据库中BSON数据的大小;
storageSize还包括数据库为集合增长预留的空间大小,以及未删除的空间;
indexSize是数据库缩印的总空间。
集合
集合是结构或者概念上相似的文档的容器。
MongoDB创建集合也是隐式的,在插入文档的时候才会创建。但因为有多重集合类型的存在,所以也提供了创建集合的命令:db.createCollection(“users”);
从MongoDB内部来讲,集合名字是通过其命名空间名字来区分的,包含所属的数据库的名字。
盖子集合
有上限的集合,有固定的大小;这意味着如果盖子集合的size达到上限,后续的插入会覆盖最先插入的文档。
除了size大小限制,MongoDB允许为盖子集合指定最大文档数量的max参数。不过size大小配置具有优先权。
TTL集合
MongoDB也允许在特定的时间后废弃文档数据,叫做Time-To-Live(TTL)集合。这个功能实际上是通过一个特殊的索引实现的。
db.logs.createIndex({time_field: 1}, {expireAfterSeconds: 3600});
该命令在time_field上创建索引,该索引会定期检查时间戳,与当前时间戳比较,如果大于expireAfterSeconds的时间设置,则会删除文档。
系统集合
MongoDB的部分设计依赖于内部集合的使用。
有两个特殊的集合:system.namespaces和system.indexes。
system.namespaces中可以查询当前数据库定义的所有命名空间。
system.indexes存储了当前数据库中定义的所有索引。
这两个集合都是标准集合,调试的时候很有用。
文档
所有的文档再被发送给MongoDB之前都序列化为BSON格式,以后再从BSON反序列化。
在MongoDB中,与关系型数据库不同,行名和列名不是分开的。key名会保存到每一个文档中,因此key名要尽量简短,这样可以节省空间(数据量庞大的情况下效果明显)。
字符串
所有的字符串都必须使用UTF-8编码。
数字
BSO内指定三种数据类型,分别是double、int、long。
JavaScript仅支持Number类型,所以MongoDB中如果要指定数据类型,要是用NumberLong()和NumberInt()强制指定。