一特点
学习一个东西, 至少首先得知道它能做什么? 适合做什么? 有什么优缺点吧?
传统关系型数据库, 遵循三大范式即原子性唯一性每列与主键直接关联性但是后来人们慢慢发现, 不要把这些数据分散到多个表节点或实体中, 将这些信息收集到一个非规范化 (也就是文档) 的结构中会更有意义尽管两个或两个以上的文档有可能会彼此产生关联, 但是通常来讲, 文档是独立的实体能够按照这种方式优化并处理文档的数据库, 我们称之为文档数据库
设计 MongoDB 的初衷就是用作分布式数据库
MongoDB 的优点:
1 性能优越 MongoDB 在各方面的设计都旨在保持它的高性能, MongoDB 能对文档进行动态填充(dynamic padding), 也能预分配数据文件以利用额外的空间来换取稳定的性能 MongoDB 把尽可能多的内存用作缓存(cache), 试图为每次查询自动选择正确的索引
2 丰富的数据类型采用 BSON 形式存储几乎你想要的数据类型是怎么样的, 存在 Mongo 里面就会是什么样的避免像关系型数据那样分 table, 然后使用的时候再 join
3 易于扩展 MongoDB 的设计采用横向扩展面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割 MongoDB 能自动处理跨集群的数据和负载, 自动重新分配文档, 以及将用户请求路由到正确的机器上
MongoDB 的缺点:
1 不支持事务 MongoDB 牺牲了数据库的事务性以追求性能的提升
2 无法进行关联操作不适用于关系复杂的数据
应用场景 : 主要解决海量数据的访问效率问题适合进行大数据存储, 而且数据的更新和删除尽可能少 (避免造成磁盘碎片) 比如我们公司的系统用它来存储司机的定位点信息, 15 秒上传一次, 自定义的 BSON 格式, 后期主要是查询相关数据, 修改较少
二基础知识
1 文档
文档是 MongoDB 的核心概念, 文档就是键值对的一个有序集
文档的键是字符串; 不能含有 \ 0(空字符), 这个字符用于表示键的结尾; 不能使用系统保留的 . 和 $; 键不能重复
文档的值可以是任意的 MongoDB 支持的类型
MongoDB 的键值对不但区分类型, 而且区分大小写, 并且是有序的 "3" 和 3 表示不同的值 "foo" 和 "Foo" 表示不同的值{"x" : 1, "y"
:2}与{"y": 2, "x": 1}是不同的
2 集合
集合就是一组文档如果把 MongoDB 的一个文档比喻成关系数据库中的一行, 那么一个集合就相当于一张表不同于表的是, 一个集合里面的文档可以是各式各样的, 例如, 下面两个文档可以存储在同一个集合里面:
- {"greeting" : "Hello, world!"}
- {"foo" : 5}
尽管如此, 从开发管理以及后面的优化来考虑还是不赞同将各式各样的文档不加区分地放在一个集合里强烈建议把相关类型的文档组织在一起!
组织集合的一种惯例是使用 "." 分隔不同命名空间的子集合例如, 一个具有博客功能的应用可能包含两个集合, 分别是 blog.posts 和 blog.authors 这是为了使组织结构更清晰, 这里的 blog 集合 (这个集合甚至不需要存在) 跟它的子集合没有任何关系
在 MongoDB 中, 使用子集合来组织数据非常高效, 值得推荐
3 数据库
在 MongoDB 中, 多个文档组成集合, 而多个集合可以组成数据库
要记住一点, 数据库最终会变成文件系统里的文件, 而数据库名就是相应的文件名, 所以数据库名有诸多限制
系统预留数据库:
admin
从身份验证的角度来讲, 这是 root 数据库如果将一个用户添加到 admin 数据库, 这个用户将自动获得所有数据库的权限再者, 一些特定的服务器端命令也只能从 admin 数据库运行, 如列出所有数据库或关闭服务器
local
这个数据库永远都不可以复制, 且一台服务器上的所有本地集合都可以存储在这个数据库中
config
MongoDB 用于分片设置时, 分片信息会存储在 config 数据库中
4 数据类型
MongoDB 在保留 JSON 基本键 / 值对特性的基础上, 添加了一些数据类型
null
-- 表示空值或者不存在的字段
boolean
-- 布尔类型有两个值 true 和 false
数值
-- shell 默认使用 64 位浮点型数值可使用 NumberInt 类 (表示 4 字节带符号整数) 或 NumberLong 类(表示 8 字符带符号整数)
- -- {"x" : NumberInt("3")}
- -- {"x" : NumberLong("3")}
字符串
日期
-- 日期存储为新纪元以来经过的毫秒数, 不存储时区
数组
-- 数组可以包含不同数据类型的元素
对象(内嵌文档)
-- {"x" : {"foo" : "bar"}}
对象 id
-- 对象 id 是一个 12 字节的 ID, 是文档的唯一标识
-- {"x" : ObjectId()}
二进制数据
-- 如果要将非 UTF- 8 字符保存到数据库中, 二进制是唯一的方式
代码
-- 查询和文档中可以包括任意 JavaScript 代码
- -- {"x" : function() { /* ... */ }}
三创建更新和删除文档
1 插入(insert)
插入单条: db.foo.insert({"bar" : "baz"})
批量插入: db.foo.batchInsert([{"_id" : 0}, {"_id" : 1}, {"_id" : 2}])
当前版本的 MongoDB 能接受的最大消息长度是 48 MB, 所以在一次批量插入中能插入的文档是有限制的如果试图插入 48 MB 以上的数据, 多数驱动程序会将这个批量插入请求拆分为多个 48 MB 的批量插入请求
如果在执行批量插入的过程中有一个文档插入失败, 那么在这个文档之前的所有文档都会成功插入到集合中, 而这个文档以及之后的所有文档全部插入失败
2 删除(remove)
db.foo.remove()
-- 会删除 foo 集合中的所有文档但是不会删除集合本身, 也不会删除集合的元信息接受一个查询文档作为可选参数
db.foo.drop()
--
整个集合都被
删除, 所有元数据也都不见
$pop(针对数组)
-- $pop 可以从数组任何一端删除元素
{"$pop":{"key":1}} 从数组末尾删除一个元素
{"$pop":{"key":-1}} 则从头部删除
$pull(针对数组)
-- $pull 删除数组中满足条件的元素
-- db.lists.update({}, {"$pull" : {"todo" : "laundry"}}) 将数组中 todo 键 等于 laundry 的元素全部剔除掉即 数组中不会有 "todo" : "laundry" 这个键值对了
3 修改(update)
- db.collection.update(
- <query>,
- <update>,
- upsert: <boolean>,
- multi: <boolean>,
- writeConcern: <document>
- )
update 有两个必选参数, 一个是查询文档, 用于定位需要更新的目标文档; 另一个是修改器文档, 用于说明要对找到的文档进行哪些修改
update 有三个可选参数, upsert : 可选, 这个参数的意思是, 如果不存在 update 的记录, 是否插入 objNew,true 为插入, 默认是 false, 不插入 multi : 可选, mongodb 默认是 false, 只更新找到的第一条记录, 如果这个参数为 true, 就把按条件查出来多条记录全部更新 writeConcern : 可选, 抛出异常的级别
MongoDB 的修改删除保存都是原子性的更新操作是不可分割的: 若是两个更新同时发生, 先到达服务器的先执行, 接着再执行另外一个所以文档的最终结果取决于最后时间执行的更新操作
- $inc
- db.analytics.update({"url" : "www.example.com"},{"$inc" : {"pageviews" : 1}})
-- 匹配到 url 等于 www.example.com 的文档, 将它的字段 pageviews 加 1
-- $inc 只能用于整型长整型或 双精度浮点型的值
$set
-- $set 用来指定一个字段的值, 如果这个字段不存在, 则创建它
db.users.update({"_id" : ObjectId("4b253b067525f35f94b60a31")},{"$set" : {"favorite book" : "War and Peace"}})
-- $set 甚至可以修改键的类型
db.users.update({"name" : "joe"},{"$set" : {"favorite book" :["Cat's Cradle","Foundation Trilogy","Ender's Game"]}})
-- $unset 将一个键完成删除
- db.users.update({"name" : "joe"},{"$unset" : {"favorite book" : 1}})
- $push (针对数组)
-- 如果数组已经存在,$push 会向已有的数组末尾加入一个元素, 要是没有就创建一个新的数组
- db.blog.posts.update(
- {"title" : "A blog post"},
- {"$push" :
- {"comments" :{"name" : "bob", "email" : "bob@example.com","content" : "good post."}}
- })
-- 使用 $each 操作符, 可以通过 $push 操作添加多个值
- db.blog.posts.update(
- {"title" : "A blog post"},
- {"$push" :
- {"comments" : $each:[
- {"name" : "bob", "email" : "bob@example.com","content" : "good post."},
- {"name" : "job", "email" : "job@example.com","content" : "job post."}]}
- })
- $addToSet(针对数组)
-- $addToSet 添加值到一个数组中去, 如果数组中已经存在该值那么将不会有任何的操作
db.users.update({"_id" : ObjectId("4b2d75476cc613d5ee930164")},{"$addToSet" : {"emails" : "joe@gmail.com"}})
4 保存(save)
save 是一个 shell 函数, 如果文档不存在, 它会自动创建文档; 如果文档存在, 它就更新这个文档它只有一个参数: 文档要是这个文档含有 "_id" 键, save 会调用 upsert 否则, 会调用 insert
5findAndModify
findAndModify 可以在一个操作中返回匹配结果并进行更新这对于操作队列 以及 执行其他需要进行原子性取值 和赋值的操作来说, 十分方便
findAndModify 命令有很多可以使用的字段:
findAndModify -- 字符串, 集合名
query -- 查询文档, 用于检索文档的条件
sort -- 排序结果的条件
update -- 修改器文档, 用于对匹配的文档进行更新(update 和 remove 必须指定一个)
remove -- 布尔类型, 表示是否删除文档(remove 和 update 必须指定一个)
new -- 布尔类型, 表示返回更新前的文档还是更新后的文档默认是更新前的文档
fields -- 文档中需要返回的字段(可选)
upsert -- 布尔类型, 值为 true 时表示这是一个 upsert 默认为 false
- db.runCommand({"findAndModify" : "processes",
- "query" : {"status" : "READY"},
- "sort" : {"priority" : -1},
- "update" : {"$set" : {"status" : "RUNNING"}}})
- db.runCommand({"findAndModify" : "processes",
- "query" : {"status" : "READY"},
- "sort" : {"priority" : -1},
- "remove" : true})
来源: https://www.cnblogs.com/jmcui/p/8604823.html