最近因为有大量的硬件数据要存储 所以公司用到了mongoDB
也git一下mongoDB的技术
mongoDB是什么
mongodb非关系型数据库
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。旨在为 WEB 应用提供可扩展
的高性能数据存储解决方案。 在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档, 数组及文档数组。
MongoDB属于面向文档的数据库
mongo权限
//创建超级用户管理员
db.createUser({
user:'root',
pwd:'root',
roles:[
{
role:'userAdminAnyDatabase',
db:'admin'
}
]
})
//给数据表创建用户
use admin
db.createUser({
user:'username',
pwd:'password',
roles:[
{
role:'readWrite',
db:'admin'
},
{
role:'Read',
db:'admin'
}
]
})
Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以在指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root:只在admin数据库中可用。超级账号,超级权限
//查看当前有哪些用户
> db.getUsers()
[
{
"_id" : "admin.admin",
"userId" : UUID("b403681c-9313-4a70-8b64-414bd6cf8dad"),
"user" : "admin",
"db" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
},
{
"role" : "readWriteAnyDatabase",
"db" : "admin"
}
],
"mechanisms" : [
"SCRAM-SHA-1",
"SCRAM-SHA-256"
]
},
{
"_id" : "admin.root",
"userId" : UUID("0f44a883-0b64-4d3e-9983-b7e9c3ba36d0"),
"user" : "root",
"db" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
],
"mechanisms" : [
"SCRAM-SHA-1",
"SCRAM-SHA-256"
]
}
]
#用户管理
db.auth() //对用户进行数据库身份验证。
db.changeUserPassword() //更改现有用户的密码。
db.createUser() //创建新用户。
db.dropUser() //删除单个用户。
db.dropAllUsers() //删除与数据库关联的所有用户。
db.getUser() //返回有关指定用户的信息。
db.getUsers() //返回有关与数据库关联的所有用户的信息。
db.grantRolesToUser() //向用户授予角色及其权限。
db.removeUser() //废弃。从数据库中删除用户。
db.revokeRolesFromUser() //从用户中删除角色。
db.updateUser() //更新用户数据。
passwordPrompt() //提示密码作为直接在各种mongo shell用户身份验证/管理方法中指定密码的替代方法。
#角色管理
db.createRole() //创建角色并指定其权限。
db.dropRole() //删除用户定义的角色。
db.dropAllRoles() //删除与数据库关联的所有用户定义的角色。
db.getRole() //返回指定角色的信息。
db.getRoles() //返回数据库中所有用户定义角色的信息。
db.grantPrivilegesToRole() //将权限分配给用户定义的角色。
db.revokePrivilegesFromRole() //从用户定义的角色中删除指定的权限。
db.grantRolesToRole() //指定用户定义的角色从中继承权限的角色。
db.revokeRolesFromRole() //从角色中删除继承的角色。
db.updateRole() //更新用户定义的角色。
创建删除数据库
创建数据库
# 创建数据库
use DATABASE_NAME //可以理解为切换到某个数据库 use 数据库名称(需要创建的数据库名称)
//如果数据库不存在,则创建数据库,否则切换到指定数据库。
进入我安装在docker中的mongoDB
创建一个DEMO数据库
插入一个文档
查询数据库
[root@localhost ~] docker exec -it mongo bash //进入mongo容器
root@9657b471c604: mongo -u admin -p 123456 //进入数据库
MongoDB shell version v4.4.2
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("8032fd4d-960e-488d-9b30-84559e0621a7") }
MongoDB server version: 4.4.2
> show dbs //查询当前所有数据库
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB
> use DEMO //(创建)进入DEMO库
switched to db DEMO
> show dbs //查询所有数据库
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB
> db //查询当前所在数据库
DEMO
> db.createCollection('demo') //在DEMO库中创建demo集合
{ "ok" : 1 }
> show dbs //再次查询当前数据库 DEMO数据库成功创建
DEMO 0.000GB
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB
删除数据库
#删除当前数据库
db.dropDatabase() //删除当前数据库(需要有相应的权限)
创建删除集合
创建集合
#创建集合
db.createCollection(name, options)
//name: 要创建的集合名称
//options: 可选参数, 指定有关内存大小及索引的选项
options 可以是如下参数:
capped | 布尔 | (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。 |
autoIndexId | 布尔 | 3.2 之后不再支持该参数。(可选)如为 true,自动在 _id 字段创建索引。默认为 false。 |
size | 数值 | (可选)为固定集合指定一个最大值,即字节数。 如果 capped 为 true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
在插入文档时,MongoDB 首先检查固定集合的 size 字段,然后检查 max 字段。
删除集合
#删除集合
db.collection.drop() //collection为删除集合名称
如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
show collections //通过show collections来查看当前集合
对文档的增删改
添加文档
#添加文档
db.COLLECTION_NAME.save(document) //如果_id 主键存在则更新数据,如果不存在就插入数据。该方法已废 弃
db.COLLECTION_NAME.insert(document) // 若插入的数据主键已经存在,则会抛 DuplicateKeyException 异常,提示主键重复,不保存当前数据。
db.collection.insertOne() //向指定集合中插入一条文档数据
db.collection.insertMany() //向指定集合中插入多条文档数据
//也可以添加数组
var arr = [];
for(var i=1 ; i<=20000 ; i++){
arr.push({num:i});
}
db.number.insert(arr);
//执行结果
> OK
> 时间: 0.716s
db.number.insertOne({"a": 3});
> OK
> 时间: 0.003s
db.number.insertMany([{"b": 3}, {'c': 4}])
> OK
> 时间: 0.003s
如果操作时没有该集合 那就会创建一个然后插入文档
执行以后会多出该集合
修改文档
#修改文档
db.collection.update( //update方法
<query>, //query : update的查询条件,类似sql update查询内where后面的。
<update>, //update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理 解为sql update查询内set后面的
{
upsert: <boolean>, //upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入 objNew,true为插入,默认是false,不插入。
multi: <boolean>, //multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个 参数为true,就把按条件查出来多条记录全部更新。
writeConcern: <document> //writeConcern :可选,抛出异常的级别。
}
)
db.number.update(
{"num":10},
{$set:
{'num':'1000'
}})
> OK
> 时间: 0.003s
成功操作
save方法
db.collection.save( //save方法
<document>, //document : 文档数据。
{
writeConcern: <document> //writeConcern :可选,抛出异常的级别。
}
)
save() 方法通过传入的文档来替换已有文档,_id 主键存在就更新,不存在就插入。
db.collection.save( //感觉有bug这个方法
<document>,
{
writeConcern: <document>
}
)
//document : 文档数据。
//writeConcern :可选,抛出异常的级别。
db.collection.updateOne() //向指定集合更新单个文档
db.collection.updateMany() //向指定集合更新多个文档
db.integer.updateOne({"b":3},{$set:{"age":"28"}}) //单条数据
db.integer.updateMany({"c":4},{$set:{"status":"xyz"}}) //多条数据
NONE: 没有异常抛出
NORMAL: 仅抛出网络错误异常,没有服务器错误异常
SAFE: 抛出网络错误异常、服务器错误异常;并等待服务器完成写操作。
MAJORITY: 抛出网络错误异常、服务器错误异常;并等待一个主服务器完成写操作。
FSYNC_SAFE: 抛出网络错误异常、服务器错误异常;写操作等待服务器将数据刷新到磁盘。
JOURNAL_SAFE: 抛出网络错误异常、服务器错误异常;写操作等待服务器提交到磁盘的日志文件。
REPLICAS_SAFE: 抛出网络错误异常、服务器错误异常;等待至少2台服务器完成写操作。
删除文档
三种删除方式
remove() #方法已经过时了
deleteOne() //官方推荐
deleteMany() //官方推荐
db.inventory.deleteMany({}) //删除集合下全部文档:
db.integer.deleteMany({ "age" : "28" }) //删除 age为28的全部文档
db.integer.deleteOne( { "b": 3 } ) //删除b=3的一个文档
查询文档数据
#find()查询 非格式化查询 格式化查询加.pretty()
db.collection.find(query, projection)
//query :可选,使用查询操作符指定查询条件
//projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省 略)。
db.data.find().pretty() //格式化查询data集合中的全部数据
db.data.findOne() //只查询一条数据
比较查询
操作 | 格式 | 范例 | RDBMS中的类似语句 |
等于 |
|
|
|
小于 |
|
|
|
小于或等于 |
|
|
|
大于 |
|
|
|
大于或等于 |
|
|
|
不等于 |
|
|
|
db.number.find({"num":{$lt:500}}).pretty() //查询number中num小于500的文档
#也可以多个条件查询
db.data.find({"url":"http://www.baidu.com","by":"4"}).pretty()
//查询url为http://www.baidu.com和by=4的数据
OR条件查询
db.col.find(
{
$or: [
{key1: value1}, {key2:value2} //或
]
}
).pretty()
db.data.find(
{
$or: [
{"url":"http://www.baidu.com"}, {"by":"4"}
]
}
).pretty()
projection 参数的使用方法
db.collection.find(query, {title: 1, by: 1}) // 只返回title by字段
db.collection.find(query, {title: 0, by: 0}) // 不返回title by字段
db.data.find({},{by:1}).pretty() //只显示by字段
db.data.find({},{by:0,title:0}).pretty() //不显示title by字段
只可以全是0或者全是1
大于 50 小于 80 只能写成
db.number.find( { num: { $gt: 50 ,$lt: 80}} )
模糊查询
#模糊查询
查询 title 包含"教"字的文档:
db.col.find({title:/教/})
查询 title 字段以"教"字开头的文档:
db.col.find({title:/^教/})
查询 titl e字段以"教"字结尾的文档:
db.col.find({title:/教$/})
查询字段数据类型
检索集合中匹配的数据类型
db.col.find({"title" : {$type : 2}}) //获取 "col" 集合中 title 为 String 的数据
#或者
db.col.find({"title" : {$type : 'string'}})
db.data.find({"by" : {$type : 'string'}},{by:1}) //查询by为string类型的文档
Limit与Skip方法
limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。
db.data.find().limit(1).pretty() 查询一条数据
skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
原本数据
db.data.find().limit(2).skip(3) //查询取两条 跳过前三条 最后结果就是最后一条
排序sort()方法
sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。
db.COLLECTION_NAME.find().sort({KEY:1})
不排序的查询
db.data.find().sort({by:1}) //按照by字段升序
索引
createIndex() 方法
注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex(),之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。
语法
db.collection.createIndex(keys, options)
// Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可
/设置索引
db.data.createIndex({"title":1}) //设置title为升序索引
//1、查看集合索引
db.col.getIndexes()
//2、查看集合索引大小
db.col.totalIndexSize()
//3、删除集合所有索引
db.col.dropIndexes()
//4、删除集合指定索引
db.col.dropIndex("索引名称")
//利用 TTL 集合对存储的数据进行失效时间设置:经过指定的时间段后或在指定的时间点过期,MongoDB 独立线程去清除数据。类似于设置定时自动删除任务,可以清除历史记录或日志等前提条件,设置 Index 的关键字段为日期类型 new Date()。
//例如数据记录中 createDate 为日期类型时:
/*设置时间180秒后自动清除。
设置在创建记录后,180 秒左右删除。*/
db.col.createIndex({"createDate": 1},{expireAfterSeconds: 180})
//由记录中设定日期点清除。
//设置 A 记录在 2019 年 1 月 22 日晚上 11 点左右删除,A 记录中需添加 "ClearUpDate": new Date('Jan 22, 2019 23:00:00'),且 Index中expireAfterSeconds 设值为 0。
db.col.createIndex({"ClearUpDate": 1},{expireAfterSeconds: 0})
#其他注意事项:
索引关键字段必须是 Date 类型。
非立即执行:扫描 Document 过期数据并删除是独立线程执行,默认 60s 扫描一次,删除也不一定是立即删除成功。
单字段索引,混合索引不支持。
聚合函数
aggregate() 类似 SQL 语句中的 count(*)。
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
$sum | 计算总和。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : {url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : {url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : {url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : {url"}}}]) |
按日、按月、按年、按周、按小时、按分钟聚合操作如下:
db.getCollection('m_msg_tb').aggregate(
[
{$match:{m_id:10001,mark_time:{$gt:new Date(2017,8,0)}}},
{$group: {
_id: {$dayOfMonth:'$mark_time'},
pv: {$sum: 1}
}
},
{$sort: {"_id": 1}}
])
时间关键字如下:
- $dayOfYear: 返回该日期是这一年的第几天(全年 366 天)。
- $dayOfMonth: 返回该日期是这一个月的第几天(1到31)。
- $dayOfWeek: 返回的是这个周的星期几(1:星期日,7:星期六)。
- $year: 返回该日期的年份部分。
- $month: 返回该日期的月份部分( 1 到 12)。
- $week: 返回该日期是所在年的第几个星期( 0 到 53)。
- $hour: 返回该日期的小时部分。
- $minute: 返回该日期的分钟部分。
- $second: 返回该日期的秒部分(以0到59之间的数字形式返回日期的第二部分,但可以是60来计算闰秒)。
- $millisecond:返回该日期的毫秒部分( 0 到 999)。
- $dateToString: { $dateToString: { format: , date: } }。
db.getCollection('m_msg_tb').aggregate(
[
{$match:{m_id:10001,mark_time:{$gt:new Date(2017,8,0)}}},
{$group: {
_id: {$dayOfMonth:'$mark_time'},
pv: {$sum: 1}
}
},
{$sort: {"_id": 1}}
])
时间关键字如下:
- $dayOfYear: 返回该日期是这一年的第几天(全年 366 天)。
- $dayOfMonth: 返回该日期是这一个月的第几天(1到31)。
- $dayOfWeek: 返回的是这个周的星期几(1:星期日,7:星期六)。
- $year: 返回该日期的年份部分。
- $month: 返回该日期的月份部分( 1 到 12)。
- $week: 返回该日期是所在年的第几个星期( 0 到 53)。
- $hour: 返回该日期的小时部分。
- $minute: 返回该日期的分钟部分。
- $second: 返回该日期的秒部分(以0到59之间的数字形式返回日期的第二部分,但可以是60来计算闰秒)。
- $millisecond:返回该日期的毫秒部分( 0 到 999)。
- $dateToString: { $dateToString: { format: , date: } }。
当 match 条件和 group 同时存在时,顺序会影响检索结果,必须先写 match 在前面。