MongoDB基础
MongoDB是一个开源, 高性能, 无模式的文档型数据库, 用于简化开发和方便扩展, 属于NoSQL数据库,是最像关系型数据库(MySQL)的非关系型数据库。
MongoDB中的记录是一个文档, 它是一个由字段和值对(field:value)组成的数据结构。
MongoDB文档类似于JSON对象, 即一个文档认为就是一个对象。
字段的数据类型是字符型, 它的值除了使用基本的一些类型外, 还可以包括其他文档, 普通数组和文档数组。
MongoDB 数据模型是面向文档的, 所谓文档就是一种类似于 JSON 的结构。
数据库 (database):一个仓库, 存储集合 (collection)
集合 (collection):类似于数组, 在集合中存放文档
文档 (document):文档型数据库的最小单位, 通常情况, 我们存储和操作的内容都是文档
在 MongoDB 中, 数据库和集合都不需要手动创建, 当创建文档时, 如果文档所在的集合或者数据库不存在, 则会自动创建数据库或者集合。




MongoDB 的特点:
高性能:
提供高性能的数据持久化
嵌入式数据模型的支持减少了数据库系统上的 I/O 活动
索引支持更快的查询, 可包含来自嵌入式文档和数组的键
mmapv1, wiredtiger等多引擎支持满足各种场景需求
Gridfs 解决文件存储需求
高可用:
MongoDB 的复制工具称作副本集 (replica set) 可以提供自动故障转移和数据冗余
高扩展:
水平扩展
分片将数据分布在一组集群的机器上 (海量数据存储,服务能力水平扩展)
MongoDB 支持基于片键创建数据区域,在一个平衡的集群当中, MongoDB 将一个区域所覆盖的读写只定向到该区域的那些片
其他:
MongoDB支持丰富的查询语言, 支持读和写操作(CRUD), 比如数据聚合, 文本搜索和地理空间查询等. 无模式(动态模式), 灵活的文档模型
基本常用命令
数据库操作
默认保留的数据库
admin: ,被添加到root数据库的用户自动继承所有数据库的权限, 一些特定的服务器端命令也只能从这个数据库运行, 比如列出所有的数据库或者关闭服务器
local: 数据永远不会被复制, 用来存储限于本地的单台服务器的集合 (部署集群, 分片等)
config: Mongo用于分片设置时, config数据库在内部使用, 用来保存分片的相关信息
文档基本 CRUD
创建 Create
db.<collection_name>.insertOne() 向集合中添加一个文档, 参数一个json 格式的文档
db.<collection_name>.insertMany() 向集合中添加多个文档, 参数为 json 文档数组
db.collection.insert({
<document or array of documents>,
writeConcern: <document>,
ordered: <boolean>
})
// 向集合中添加一个文档
db.collection.insertOne(
{ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
// 向集合中添加多个文档
db.collection.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
{ item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
])
注:向 collection 中插入 document 文档时, 如果没有给文档指定 _id 属性, 数据库会为文档自动添加 _id field, 并且值类型是 ObjectId(blablabla), 就是文档的唯一标识。
mongo 中的数字, 默认情况下是 double 类型, 如果要存整型, 必须使用函数NumberInt(整型数字), 否则取出来就有问题。
插入当前日期可以使用 new Date()
如果某条数据插入失败, 将会终止插入, 但已经插入成功的数据不会回滚掉. 可以使用 try catch 进行异常捕捉处理, 测试的时候可以不处理.如:
try {
db.comment.insertMany([
{……}{……}
]);
} catch (e) {
print (e);
}
查询 Read
db.<collection_name>.find() 接受一个 json 格式的查询条件. 返回一个数组
db.<collection_name>.findOne() 查询集合中符合条件的第一个文档, 返回一个对象
操作符:
在 terminal 中查看结果可能不是很方便,可用 pretty() 来帮助阅读
db.inventory.find().pretty()
匹配内容
db.posts.find({
comments: {
$elemMatch: {
user: 'Harry Potter'
}
}
}).pretty()
// 正则表达式
db.<collection_name>.find({ content : /once/ })
创建索引
db.posts.createIndex({
{ title : 'text' }
})
// 文本搜索
db.posts.find({
$text : {
$search : "\"Post O\""
}
}).pretty()
更新 Update
db.<collection_name>.updateOne(<filter>, <update>, <options>) :修改一个匹配 <filter> 条件的文档
db.<collection_name>.updateMany(<filter>, <update>, <options>) :修改所有匹配 <filter> 条件的文档
db.<collection_name>.replaceOne(<filter>, <update>, <options>) :替换一个匹配 <filter> 条件的文档
db.<collection_name>.update(查询对象, 新对象):默认情况下会使用新对象替换旧对象
db.document.update({ userid: "30", { $set {username: "guest"} } })//默认修改第一条
db.document.update({ userid: "30", { $set {username: "guest"} } }, {multi: true})//修改所有符合条件的
其中 <filter> 参数与查询方法中的条件参数用法一致.
db.<collection_name>.replaceOne():替换除 _id 属性外的所有属性, 其<update>参数应为一个全新的文档.
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)

删除delete
db.collection.deleteMany() :删除所有匹配的文档.
db.collection.deleteOne() :删除单个匹配的文档.
db.collection.drop()
db.dropDatabase()
db.inventory.deleteMany( { qty : { $lt : 50 } } )
即使从集合中删除所有文档,删除操作也不会删除索引。
一般数据库中的数据都不会真正意义上的删除, 会添加一个字段, 用来表示这个数据是否被删除
文档排序 Sort
查询文档内容时, 默认是按照 _id 进行排序,可用 $sort 更改文档排序规则
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
对于要排序的字段,请将排序顺序设置为1或-1,以分别指定升序或降序排序。
db.users.aggregate(
[
{ $sort : { age : -1, posts: 1 } }
]
)
$sort运算符和内存
$sort + $limit 内存优化
当$sort在$limit之前,并且没有修改文档数量的中间阶段时,优化器可以将$limits合并为$sort。这允许$sort操作在进行过程中只维护前n个结果(n是指定的限制),并确保MongoDB只需要在内存中存储n个项目。当allowDiskUse为true且n项超过聚合内存限制时,此优化仍然适用。
优化可能会在不同版本之间发生变化。
投影 Projection
对文档进行查询并不是需要所有的字段,可对文档进行“投影”
1 - display
0 - dont display
> db.users.find( {}, {username: 1} )
> db.users.find( {}, {age: 1, _id: 0} )
forEach()
> db.posts.find().forEach(fucntion(doc) { print('Blog Post: ' + doc.title) })
正则表达式
$ db.collection.find({field:/正则表达式/})
$ db.collection.find({字段:/正则表达式/})
比较查询
<, <=, >, >= :
db.collection.find({ "field" : { $gt: value }}) //大于: field > value
db.collection.find({ "field" : { $lt: value }}) //小于: field < value
db.collection.find({ "field" : { $gte: value }}) //大于等于: field >= value
db.collection.find({ "field" : { $lte: value }}) //小于等于: field <= value
db.collection.find({ "field" : { $ne: value }}) //不等于: field != value
包含查询
包含: $in 操作符. db.comment.find({userid:{$in:["1003","1004"]}})
不包含: $nin 操作符. db.comment.find({userid:{$nin:["1003","1004"]}})
常用命令小结
选择切换数据库:use articledb
插入数据:db.comment.insert({bson数据})
查询所有数据:db.comment.find();
条件查询数据:db.comment.find({条件})
查询符合条件的第一条记录:db.comment.findOne({条件})
查询符合条件的前几条记录:db.comment.find({条件}).limit(条数)
查询符合条件的跳过的记录:db.comment.find({条件}).skip(条数)
修改数据:db.comment.update({条件},{修改后的数据})
或db.comment.update({条件},{$set:{要修改部分的字段:数据})
修改数据并自增某字段值:db.comment.update({条件},{$inc:{自增的字段:步进值}})
删除数据:db.comment.remove({条件})
统计查询:db.comment.count({条件})
模糊查询:db.comment.find({字段名:/正则表达式/})
条件比较运算:db.comment.find({字段名:{$gt:值}})
包含查询:db.comment.find({字段名:{$in:[值1, 值2]}})
或db.comment.find({字段名:{$nin:[值1, 值2]}})
条件连接查询:db.comment.find({$and:[{条件1},{条件2}]})
或 db.comment.find({$or:[{条件1},{条件2}]})
文档间的对应关系:一对一、一对多、多对多
MongoDB 的索引
MongoDB 可使用索引限制必须检查的文档数.
MongoDB 使用的是 B Tree, MySQL 使用的是 B+ Tree
db.<collection_name>.createIndex({ userid : 1, username : -1 })
db.<collection_name>.getIndexes()
db.<collection_name>.dropIndex(index)
db.<collection_name>.dropIndex( "userid_1_username_-1" )
db.<collection_name>.dropIndex({ userid : 1, username : -1 })
db.<collection_name>.dropIndexes()
索引的类型:
单字段索引 Single Field Index
复合索引 Compound Index
地理空间索引(Geospatial Index):返回结果时使用平面几何的二维索引、使用球面几何的二维球面索引
文本索引(Text Indexes):支持在集合中搜索字符串内容.这些文本索引不存储特定于语言的停止词(例如 “the”), 而将集合中的词作为词干, 只存储根词.
哈希索引(Hashed Indexes):为了支持基于散列的分片, MongoDB 提供了散列索引类型, 它对字段值的散列进行索引.这些索引在其范围内的值分布更加随机, 但只支持相等匹配, 不支持基于范围的查询.
索引的查看:db.collection.getIndexes()
默认 _id 索引: MongoDB 在创建集合的过程中, 在 _id 字段上创建一个唯一的索引, 默认名字为 _id , 该索引可防止客户端插入两个具有相同值的文档.
该索引是唯一索引, 因此值不能重复, 即 _id 值不能重复的.
在分片集群中, 通常使用 _id 作为片键.
索引的创建:db.collection.createIndex(keys, options)
参数
Parameter
Type
Description
keys
document
包含字段和值对的文档。字段是索引键,值描述该字段的索引类型。升序:1;降序:-1。如:({字段:1或-1}。MongoDB支持不同的索引类型:文本、地理空间和哈希索引。
options
document
可选。包含一组控制索引创建的选项的文档。

注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex() , 之后的版本使用了 db.collection.createIndex() 方法, ensureIndex() 还能用, 但只是 createIndex() 的别名.
索引的删除
# 删除某一个索引:$ db.collection.dropIndex(index)
# 删除全部索引:$ db.collection.dropIndexes()
索引使用
执行计划
分析查询性能 (Analyze Query Performance) 通常用执行计划 (解释计划 - Explain Plan) 来查看查询的情况
$ db.<collection_name>.find( query, options ).explain(options)
比如: 查看根据 user_id 查询数据的情况
"stage" : "COLLSCAN", 表示全集合扫描
"stage" : "IXSCAN", 基于索引的扫描
涵盖的查询
当查询条件和查询的投影仅包含索引字段时, MongoDB 直接从索引返回结果, 而不扫描任何文档或将文档带入内存, 这些覆盖的查询十分有效。