NoSQL基础部分
一、NoSQL相关概念
1、NoSQL定义
Not only SQL
2、时间单位
1s=10^3 ms=10^6 um=10^9 ns
3、存储数据单位
B、KB、MB、TB、PB、EB、ZB、YB
二、数据库分类
1、TRDB数据库
2、NoSQL数据库
- 键值数据库
- 文档数据库
- 列族数据库
- 图数据库
- 其他数据库
3、NewSQL
三、
1、帽子定理
- 一致性
- 可用性
- 分区容错性
2、ACID
- 原子性
- 一致性
- 隔离性
- 持久性
3、BASE
- 基本可用
- 软状态
- 最终一致性
四、NoSQL存储模式
1、键值数据存储模式
基本要素:键、值、键值对、命名空间
操作:读、写、删除
优点:简单、快速、高效计算
缺点:对值进行多值查找功能很弱;缺少约束,意味着更容易出错;不容易建立复杂关系
2、文档数据存储模式
基本要素:键值对、文档、集合、数据库
操作:增删改查
优点:简单;相对高效;文档格式处理;查询功能强大;分布式处理
缺点:缺少约束;数据出现冗余;相对低效
3、列族数据存储模式
基本要素:命名空间、行键、列族、列
操作:读、写、删除
特点:擅长大数据处理;对于命名空间、行键、列族需要预先定义,列无须提早定义,随时可以增加;在大数据应用环境下,管理复杂,必须借助各种高效的管理工具来监控系统的正常运行;Hadoop生态系统为基于列族的大数据分析,提供了各种开发工具;数据存储模式相对键值数据库、文档数据库要复杂;查询功能相对更加丰富;高密集写入处理能力 每秒几百万次的并发插入能力
4、图数据存储模式
基本要素:节点、边、属性、图
操作:建立、删除、更新、合并
特点;处理各种具有图结构的数据;应用领域明确;以单台服务器运行的图数据库为主;图偏重于查找、统计、分析应用
5、其他数据存储模式
1、多模式数据库
2、对象数据库
3、网格和云数据库
NoSQL实践部分
一、MongoDB shell简单操作
1、启动
mongo
mongo 127.0.0.1:27017/admin
2、退出
exit
3、创建数据库
use 数据库名
4、查看数据库
show dbs
5、查看当前数据库中的集合列表
show collections
6、统计当前数据库信息
db.stats()
7、删除当前数据库
db.dropDatabase()
8、帮助指令
# 数据库操作
db.help()
# 集合操作
db.集合名.help()
# 文档操作
db.集合名.find().help()
9、查看当前数据库下集合名称
db.getCollectionNames()
10、查看数据库用户角色权限
show roles
11、执行js文件
mongo shell_script.js
load(script_path)
二、配置用户账号和访问控制
1、角色概念
- 数据库用户角色:read、readWrite
- 数据库管理角色:dbAdmin、dbOwner、userAdmin
- 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
- 备份恢复角色:backup、restore
- 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
- 超级用户角色:root
- 内部角色:_system
read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmi:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,具有所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,具有所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,具有所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,具有所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,具有所有数据库的dbAdmin权限。
root:只在admin数据库中可用。超级账号,超级权限
2、用户操作
创建用户
use admin
db.createUser({
user: 'root',
pwd: 'root',
roles: [{"role": "root", "db": "admmin"}]
})
exit
认证登录
mongo
use admin
db.auth('root','root')
mongo admin -u root -p root
删除用户
use admin
db.dropUser("root")
三、管理数据库和集合
1、给指定数据库添加集合并添加文档
db.集合名.insert({key:value})
2、删除指定数据库中的集合
db.集合名.drop()
3、查询指定集合中的文档
db.集合名.find()
db.集合名.findOne()
4、更新文档
db.集合名.update({key:value},{$set:{key:value}})
5、删除文档
db.集合名.remove({key:value})
四、Find详细内容
1、语法
db.[Collection_Name].find({query},{projection})
db.[Collection_Name].find({query},{projection}).pretty() // 规整查找结果的格式
- query //查询条件设置:查询选择器
- projection //键指定,指定需要返回的字段:投影操作
2、查询选择器
(1)选择器匹配
db.[Collection_Name].find({<key1:value1>,{<key2:value2>,...}})
注意:无论传入多少个键值对它们必须全部匹配;查询条件之间相当于运用了布尔运算符and。
(2)范围查询
操作符 | 意义 | 符合 |
---|---|---|
$lt | less than | < |
$lte | less than or equal | <= |
$gt | greater than | > |
$gte | greater than or equal | >= |
# 查询年龄介于25到30之间的人
db.persons.find({age:{$gte:25,$lte:30}})
(3)匹配数组
操作符 | 作用 |
---|---|
$in | 与任一搜索键匹配时,就返回该文档 |
$nin | 与任一搜索键不匹配时,就返回该文档 |
$elemMatch | 至少有一个元素满足所有匹配条件,就返回该文档 |
$all | 与所有搜索键匹配,就返回文档 |
$size | 查询指定长度数组(不能与比较查询符一起使用) |
# 查询国籍是(不是)中国或美国的学生信息
db.persons.find({country:{$in:["USA","China"]}})
db.persons.find({country:{$nin:["USA","China"]}})
# 查询 80<=results<=85的文档
db.scores.find({results:{$elemMatch:{$gte:80,$lte:85}}})
# 查询喜欢看MONGODB和JS的学生
db.persons.find({books:{$all:["MONGODB","JS"]}})
# 查询第二本书是JAVA的学生信息
db.persons.find({"books.1":"JAVA"})
# 查询出书籍数量是4的学生
db.persons.find({books:{$size:4}})
(4)布尔查询
操作符 | 意义 | 备注 |
---|---|---|
$ne | 不等于 | 可以作用于单个值和数组 |
$not | 对查询结果求反 | 不能放在外层文档;后面必须跟正则表达式或者文档 |
$or | 逻辑或 | 条件1尽可能 匹配更多文档 |
$and | 连接具有and关系的复杂查询条件 | |
$exists | 查询集合中包含特定键的文档 |
# 查询国籍不是美国籍的学生信息
db.persons.find({country:{$ne:"USA"}},{_id:0,name:1,country:1})
# 查询出姓名里存在“li”的学生信息
db.persons.find({name:/li/i})
# 查询出姓名里不存在“li”的学生信息
db.persons.find({name:{$not/li/i}})
# 查询语文成绩大于85或者英语大于90的学生信息
db.persons.find({$or:[{c:{gt:85}},{e:{gt:90}}]})
# 查询国籍是中国或美国的学生信息
db.persons.find({$or:[{country:"China"},{country:"USA"}]})
db.persons.find({country:{$or:["China","USA"]}}) // 错误
db.persons.find({country:{$in:["USA","China"]}})
# 返回键名含有gender的文档
db.persons.find({gender:{$exists:true}})
# 返回键名部含有gender的文档
db.persons.find({gender:{$exists:false}})
(5)正则表达式
# $regex
{<field>:{$regex:/pattern/,$options:'<options>'}}
{<field>:{$regex:'pattern',$options:'<options>'}}
{<field>:{$regex:/pattern/<options>}}
# 正则表达式对象
{<field>:/pattern/<options>}
$in | 隐式的$and | options中包含X或S选项时 | |
---|---|---|---|
正则表达式 | √ | ||
$reges | √ | √ |
{name:{$in:[/^joe/i,/^jack/]}}
{name:{$regex:/^zh/i,$min:["zhang"]}}
{email:{$regex:/@qq./,$options:"si"}}
pattern选项 | 实例 | 比较说明 |
---|---|---|
/查询值的固定后一部分$/ | db.persons.find({name:{$regex:/ang$/}}) | where name like “%ang” |
/^查询值的固定前一部分/ | db.persons.find({name:{$regex:/^zh/}}) | where name like “zh%” |
/查询值的任意部分/ | db.persons.find({name:{$regex:/c/}}) | where name like “%c%” |
options选项 | 语法格式 | 选项说明 |
---|---|---|
i | {<field>{$regex:/pattern/i}} | 不区分大小写字母 |
m | {<field>:{$regex:/pattern/,$options:m}} | 多行匹配模式 |
x | {<field>:{$regex:/pattern/,$options:x}} | 忽略非转义的空白字符 |
s | {<field>:{$regex:/pattern/,$options:s}} | 单行匹配模式 |
(6)where操作符
// 查询年龄大于22岁,喜欢看JS书,在八一中学上过学的学生
db.persons.find({"$where":function(){
var books=this.books;
var schools=this.schools;
if(this.age>22){
for(var i=0;i<books.length;i++){
if(books[i]=="JS"){
if(schools){
for(var j=0;j<schools.length;j++)
if(schools[j].name=="八一中学"){
return true;
}
}
break;
}
}
}
}})
(7)Type操作符
3、投影
db.persons.find({},{_id:0,name:1})
# 查询出“lisi”书架上的第2~4本书
db.persons.find({name:"lisi"},{_id:0,name:1,books:{$slice:[1,3]}}) # 1:跳过元素数,2:返回元素数
# 查询出“lisi”书架上的最后一本书
db.persons.find({name:"lisi"},{_id:0,name:1,books:{$slice:-1}})
4、其他
(1)Limit返回指定的数据条数
# 查询出persons文档中前5条数据
db.persons.find().limit(5)
(2)Skip返回指定数据跨度
# 查询出persons文档中5~10条的数据
db.persons.find().limit(5).skip(5)
(3)Sort按指定属性排序
# 返回按年龄排序的数据
db.persons.find().sort({age:1}) #升序
db.persons.find().sort({age:-1}) #降序
(4)游标
var persons=db.persons.find();
while(persons.hasNext()){
obj=persons.next();
print(obj.name)
}
var ShowCursor=db.persons.find()
ShowCursor.forEach(printjson)
(5)Count计数
# 查询美国学生的人数
db.persons.find({country:"USA"}).count()
(6)Distinct查找不同的字段值
# 查询出persons中一共有多少个国家分别是什么
db.persons.distinct("country",{})
db.runCommand({distinct:"persons",key:"country"}).values
五、集合操作
1、插入文档
insert
db.collection_name.insert(<document or array of document>,{writeConcern:<document>,ordered:<boolean>})
db.collection_name.insertOne()
db.collection_name.insertMany()
save
db.collection_name.save(<document>)
2、更新文档
db.collection_name.update(<query>,<update>,{upsert:<boolean>,multi:<boolean>,writrConcern:<document>,collation:<document>})
参数名称 | |
---|---|
query | update的查询条件 |
update | update的对象和更新操作符 |
upsert | 如果不存在update的记录是否插入 |
multi | 是否更新多条记录 |
writerConcern | 自定义写出错确认级别 |
collation | 指定特定国家语言的更新归类规则 |
(1)insertOrUpdate操作
db.collection_name.update({查询器},{修改器},true) # 对应upsert参数
(2)批量更新操作
db.collection_name.update({查询器},{修改器},false,true) # false:对应upsert参数;true:对应multi参数
操作符 | |
---|---|
$set | 修改器 |
$inc | 修改数值,加法 |
$mul | 修改数值,乘法 |
$rename | 修改错误字段的键名 |
$unset | 删除指定字段 |
$min | 当前值大于指定值时,修改为指定值 |
$max | 当前值小于指定值时,修改为指定值 |
$addToSet | 若目标数组值中存在要追加的元素,则该元素不做任何操作 |
$push | 1.如果指定的键是数组,追加新的元素值 2.如果指定的键不是数组,则中断当前操作 3.如果不存在指定的键,则创建数组类型的键值对 |
$pop | 从指定数组删除一 个值: 1删除最后一个数值;-1删除第一个数值 |
$pull | 删除一个被指定的数值 |
$pullAll | 次性删除多个指定的数值 |
3、删除文档
db.collection_name.remove(<query>,{justOne:<boolean>,writeConcern:<document>,collection:<document>})
六、分组、聚合、映射-归并、复制分片
1、分组
db.runCommand({group:{
ns:集合名字,
Key:分组的键对象,
Initial:初始化累加器,
$reduce:组分解器,
Condition:条件,
Finalize:组完成器
}})
# 查出persons中每个国家学生数学成绩最好的学生信息(必须在90以上)
db.runCommand({group:{
ns:"persons",
Key:{"country":true},
Initial:{m:0},
$reduce:function(doc,prev){
if(doc.m>prev.m){
prev.m=doc.m;
prev.name=doc.name;
prev.country=doc.country;
}
},
Condition:{m:{$gt:90}}
finalize:function(prev){
prev.m=prev.name+"Math scores"+prev.m
}
}})
2、聚合
db.collection_name.aggregate({$match:{<field>}},{$group:{<field1>,<field2>}})
field1:分类字段
field2:含各种统计操作符的数值型字段( s u m , sum, sum,max,$min等)
可在aggregate()中使用的聚合运算符
运算符 | 描述 |
---|---|
$project | 通过重命名、添加或删除字段来重新定义文档。 |
$match | |
$limit | 限制传递给聚合流水线中下一个阶段的文档数 |
$skip | 指定执行聚合流水线的下一个阶段前跳过多少个文档 |
$unwind | 对指定的数组进行分拆,为其中的每一个值创建一个文档 |
$group | 将文档分组并生成一组新的文档,供流水线的下一个阶段使用 |
$sort |
可在聚合运算符$group中使用的表达式运算符
运算符 | 描述 |
---|---|
$addToSet | |
$first | 返回当前文档组中第一个文档的指定字段的值 |
$last | |
$max | |
$min | |
$avg | |
$push | |
$sum |
# 查出persons中每个国家学生数学成绩最好的学生信息(必须在90以上)
db.persons.aggregate({$match:{m:{$gte:90}}},{$group:{_id:{country:"$country",name:"$name",value:"$m"}}})
3、映射-归并
db.orders.mapReduce(
function(){emit(param1,param2);},
function(key,values){return Array.sum(values);},
{
query:{status:"A"},
out:"order_totals"
}
)
1、map部分
作用:用于分组。
param1:需要分组的字段,this.字段名。
param2:需要进行统计的字段,this.字段名。
2、reduce部分
作用:处理需要统计的字段。
key:指分组字段对应的值。
values:指需要统计的字段值组成的数组。
// 对数值类型进行求和
var reduce=function(key,values){ return Array.sum(values);}
// 对字符串类型进行拼凑
var reduce=function(key,values){ return values.join(',');}
3、options部分
query:先筛选符合条件的记录出来,再进行分组统计。
out:将分组统计后的结果输出到哪个集合中。
# 统计不同地方的人的年龄总和
var map=function(){emit(this.location,this.age);}
var reduce=function(key,valued){return Array.sum(values);}
var options={out:"age_totals"}
db.mythings.mapReduce(map,reduct,options)
# 统计不同地方的人数总和
var map=function(){emit(this.location,1);}
var reduce=function(key,valued){return Array.sum(values);}
var options={out:"person_totals"}
db.mythings.mapReduce(map,reduct,options)
# 统计不同地方的人名列表
var map=function(){emit(this.location,this.name);}
var reduce=function(key,valued){return values.join(',');}
var options={out:"name_totals"}
db.mythings.mapReduce(map,reduct,options)
# 统计不同地方并且年龄在25岁(不包括25岁)以下的人名列表
var map=function(){emit(this.location,this.name);}
var reduce=function(key,valued){return key+':'+values.join(',');}
var options={query:{age:{$lt:25}},out:"name_totals"}
db.mythings.mapReduce(map,reduct,options)
4、复制分片
七、Java连接MongoDB
package com.example.demo;
import com.mongodb.client.*;
import org.bson.Document;
public class JavaConnect {
public static void main(String[] args) {
MongoClient mg = MongoClients.create("mongodb://localhost:27017");
MongoDatabase db = mg.getDatabase("***"); // 数据库名
MongoCollection<Document> collection = db.getCollection("***"); // 集合名
FindIterable<Document> findIter = collection.find().limit(10); // 获取文档
MongoCursor<Document> cur = findIter.iterator(); // 获得迭代器
System.out.println("该单词库共有:"+collection.countDocuments()+"个单词。");
while (cur.hasNext()) { // 遍历集合
Document doc = cur.next();
System.out.println(doc.get("word"));
}
mg.close(); // 关闭连接
}
}
测试题
# 1
mongo member.js
show collections
# 2
db.member.find({},{_id:0})
# 3
db.member.find({age:{$gte:19,$lte:21}},{sno:1,sname:1,age:1,_id:0})
# 4
db.member.find({$or:[{major:"计算机科学与技术"},{major:"网络工程"}]},{sno:1,sname:1,major:1,_id:0})
# 5
db.member.distinct("major")
# 6
db.member.find().count()
# 7
db.member.find({'course.1':"python"},{_id:1,sname:1})
# 8
db.member.find({},{_id:1,sname:1,age:1}).sort({age:-1})
# 9
db.member.update({sname:"zhouyang"},{$set:{sno:"1813007",sname:"zhouyang",age:18,major:"网络工程"}},true)
# 10
db.member.update({major:"软件工程"},{$set:{location:"loc01"}},false,true)
db.member.find()
# 11
db.member.update({sno:"1813003"},{$addToSet:{course:"JSP"}})
db.member.find()
# 12
db.member.remove({major:"通信工程"},{justOne:false})
db.member.find({},{_id:0,sno:1,sname:1,major:1})
# 13
var map=function(){emit(this.major,this.sname);}
var reduce=function(key,values){return key+'>>'+values.join(',');}
var options={out:"stu1"}
db.member.mapReduce(map,reduce,options)
db.stu1.find()
# 14
db.member.aggregate({$match:{age:{$gte:18}}},{$group:{_id:"$major",age_max:{$max:"$age"}}})