学了一学期的内容整理一下
我们用的教材是人民邮电出版社出版的mongodb入门经典
复习是按照书上内容来的
mongodb真的是个很强大的数据储存和分析工具,它集储存管理分析于一身,用起来简单,都是对象.方法,而且效率还很高
可是国内似乎并没多少公司在用它,暂时应该不会再学习它了
2章
关闭数据库引擎
use admin
db.shutdownServer()
显示数据库清单
show dbs
执行脚本的方法
load()
*******************************************************
4章
创建用户
db.createUser({})
必选
user:"用户名"
roles:["",""]
pwd/userSource二选一,一般pwd:"密码"
可选
otherDBRoles:{数据库:["",""]}
用来指定用户在其他数据库中的角色
roles的值(课本提到的):
1,数据库用户角色
read,readWrite:读/读写
2,数据库管理角色
dbAdmin,userAdmin:管理文档/管理用户
上面的加AnyDatabase对所有数据库生效
3,集群管理角色
clusterAdmin:一般说到集群,就只有这个有权限
4,超级用户
root
列出用户
show users
删除用户
db.dropUser("用户名") //根据属性删的只有它,其他都是指定对象然后调用删除的方法
************************************************************
5章
这里先了解下mongodb
数据是这样存放的 数据库(集合(文档))
mongodb本身创建了一些对象,对这些对象提供了操作方法
分别是:
服务器对象:connection P67
数据库:database P68
集合:collection P69
集合的一些操作返回的对象:cursor P84
使用方法时先确定对象有这个方法,调用方式就跟java一样
所以写shell脚本时要先用实例化一个connection对象,用getDB()方法来获取数据库对象,执行操作
最后会总结一下这几个对象常用的方法,先开始第五章
第五章主要讲的是database对象和collection对象基本方法的使用,
这个对象的方法使用时先要指明对象db
创建数据库
mongodb没有直接创建数据库的方法,可以通过声明一个数据库句柄,给里面加一个空集合来实现
use 数据库
db.createCollection("集合名")
删除数据库
use 数据库
db.dropDatabase() //use了一个库,db代表的就是这个库对象
创建集合
db.createCollection("名字",可选项)
可选项类型为集合{}
属性:
autoIndexID:布尔值 类似mysql创建一个自动增长的主键用来索引,默认为true,固定集合应关掉它
capped:布尔值 是否创建固定集合,默认false
size:int 集合大小
max:int 最大文档数
这三项都是创固定集合用的,一般不用
给个例子:db.createCollection("haha",{capped:true,size:20,max:20},{autoIndexID:false})
删除集合
db.集合.drop() //这里有些奇怪,集合像是库的一个属性(也许真的是),但就是能这么获取集合对象
查看集合(我加了一种)
show collections
db.getCollectionNames() //db对象提供的,返回是一个数组,js中就可以继续处理它
这里补下添加文档的方法,书上第八章才讲
db.集合.insert(文档)
文档的格式时对象{},如果插入多个应用数组打包他们
给个例子: db.haha.insert([{name:"li",age:19},{name:"xiang",age:20}])
******************************************************************
6章
第六章讲的是查询,就是sql里的select,重要性不用说
find(query,projection) //查询并返回一个cursor对象,该对象有一堆方法来对查询结果进行加工
findOne(query,projection) //查询并返回一个文档,注意是 一个 文档
query 可选,用来对查询进行限制,具体书上P85,一会会在最后具体介绍有哪些
projection 可选,控制返回信息,对返回结果进行限制
放到sql就是
select projection where query
虽然select是对表内容操作而这里是对集合文档操作,但意义一样
看懂了上面,接下来实现具体功能就好理解了,要记的就是query运算符,query也是一个对象形式
当一个键值对作为属性时,肯定是对象形式,不会出现a:b:c的形式或a:[b:c,d:e],参考json
应该是这样的a:{b:c}或a:[{b:c,d:e}],json对象的属性可以是单个值,对象或数组
先写个集合,对它进行操作
db.hehe.insert([{name:"li",age:[{first:1,second:9}],height:190},{name:"xiang",age:[{first:2,second:0}],height:200}])
db.hehe.insert([{name:"li",age:{first:1,second:9},height:190},{name:"xiang",age:{first:2,second:0},height:200}])
看功能,结合书上P85
查看所有文档
db.集合.find()
db.hehe.find()
根据特定字段值查找文档 $ne:int/string
db.集合.find({字段:值})
db.hehe.find({name:"li"})
根据字段值数组 $in:[] $nin $all
db.集合.find({字段:{$in:[值1,值2]}})
db.hehe.find({name:{$in:["li","xiang"]}})
根据字段值大小 $gt:int $lt $gte $lte $or:[query,query]用或语句连接条件 $and且语句 $not非
db.hehe.find({height:{$gt:190}})
db.hehe.find({$or:[{height:{$gt:190}},{height:{$lt:210}}]})
根据数组字段长度$size:int
db.hehe.find({age:{$size:1}}) 可看出size指的是数组的元素数
根据子文档的值查找 .语法,这里属性要加""
db.hehe.find({"age.first":{$gt:0}})
根据字段是否存在 $exists:布尔值
db.hehe.find({name:{$exists:true}})
根据子文档数组中字段$elemMatch
db.hehe.find({age:{$elemMatch:{first:1}}})
db.hehe.find({"age.first":1}) 这俩对比一下区别
最后说个比较重要书上却没有提的 $regex:正则表达式 //支持两种格式
像sql语句就提供了通配符来实现模糊查询,而mongodb模糊查询通过正则表达式实现
db.hehe.find({name:{$regex:'g'}}) 包含g
db.hehe.find({name:{$regex:'^x.*g$'}}) x开头g结尾
db.hehe.find({name:{$regex:/g/}})
db.hehe.find({name:{$regex:/^x.*g$/}})
限制结果集返回的字段(书上在第七章才说)
前面说的都是第一个参数,现在来看第二个参数的作用
db.hehe.find({name:{$regex:/^x.*g$/}},{_id:false,age:false})
***********************************************************************************
7章
第七章主要讲find()方法返回的cursor对象的方法,这个表在第六章却第七章才开始讲
这个对象的常用方法会在最后给出
先从功能来学习,结合书上P84
计算文档数,准确说是返回的文档数
db.hehe.find().count()
结果集排序 sort(sortObj) 字段:1/-1 1升-1降
db.hehe.find().sort({name:1,height:-1}) 字符串应该是按首字母字典排序(猜)
限制返回文档数
db.hehe.find().limit(1)
结果分页
db.hehe.find().sort({name:1}).limit(2).skip(0)
db.hehe.find().sort({name:1}).limit(2).skip(2) 分两次
cursor的方法大部分都是返回cursor对象的,也就说可以多次处理sort()完还能limit()
最后突然提到了collection对象的distinct()方法,sql里也有它,就是去重
distinct(key,query)
key即字段
query就是我们在前面学的查询限制符
和sql不一样的是,它不是cursor对象,而是和find()一样的存在,所以为了能使它在去重后能特定查询,给它加了query这个参数
但和find()不同的是,他和findOne()一样,返回的是一个数组,且只返回去重的那列
db.hehe.distinct("name",{height:190})
*******************************************************************************
8章
第八章才教增删改,前面想用自己数据操作都不会插入,只能用给的字母集,坑
增前面说了
现在说改和删,还是用刚刚的例子
重要考点
update(query,updata,upsert,multi)P120
query 前面提到的查询限制符
upsert 布尔值,true,如果没匹配到文档就创个新的,任性
multi 布尔值,true,更新所有匹配到的,false,只更新第一个
update 对象,里面是要更新的内容,结合运算符实现P116,用法跟query很像,
其中query和update是必选,upsert,multi默认是false,应该是为了数据完整性考虑,默认最小程度破坏原始数据,不添加,只改一个
这块记得老师当时讲了两节课,几乎讲了所有运算符,书上没好好讲这
自己来总结功能,同样是collection的方法
$inc //课本就给了加,其他三个在哪见过忘了
db.hehe.update({},{$inc:{height:1}})
$rename //重命名
db.hehe.update({},{$rename:{name:"name1"}}) db.hehe.update({},{$rename:{name1:"name"}})改回来
$set //设置字段值,修改一个已经有的,如果没就新加一个字段
db.hehe.update({},{$set:{height1:1}}) db.hehe.update({},{$set:{height:1}})
$unset //删除字段
db.hehe.update({},{$unset:{height1:""}}) 这里就和set一样,值写""(测试写啥都会被删掉,但不能为空),
工程师偷懒了,不该是这样吗db.hehe.update({},{$unset:"height1"})
/分割 前面是对普通字段操作,下面是对嵌套字段的操作
$addToSet //给数组里添单个不重复的字段
db.hehe.update({},{$addToSet:{age:"new"}}) //这也是json数组容器的特点,里面的元素不需要相同的格式
db.hehe.update({},{$addToSet:{age:{third:"new"}}})
$pushAll //给数组添加多个字段
db.hehe.update({},{$pushAll:{age:[{four:"old"},"old"]}})
乍一看语法是一样,区别在于
1,addToSet只能插单个值
db.hehe.update({},{$addToSet:{age:[{third:"new"},"5"]}}) //它和push一样都会把这个数组当作元素插到数组里
2,addToSet只在数组里没有这个值时插入,push会重复插入
注意,匹配数组时,如果没有这个数组,会新建一个数组
$push //给数组添加单个字段
上面的数组换成单个值
$pop //删除第一个元素或最后一个元素
db.hehe.update({},{$pop:{age:-1}})
$pullAll //删除多个元素,语法和pushAll()一样
$pull
你猜
$each
对addToSet和push的值进行加工,
用法分两步
先写基本的插入db.hehe.update({name:"xiang"},{$addToSet:{age:}}) //这里本该写要查的元素,上面说了,如果元素写成数组的形式,会把它当成整体插进去
再写db.hehe.update({name:"xiang"},{$addToSet:{age:{$each:["4","5"]}}})
要实现像pushAll那样添加多个元素,就要使用$each,这样addToSet也能插入多个了,至于push,用这个也行,但哪有pushAll好用
///分割,刚刚是更新数组,最后来学更新对象
db.hehe.update({name:"xiang"},{$set:{age:{first:3}}})如果直接这么些,显然,不会把first值改为3,而是把age值改为{first:3}
db.hehe.update({name:"xiang"},{$set:{age:{first:1,second:3}}}) 先改回去
db.hehe.update({name:"xiang"},{$set:{"age.first":3}}) 其实在find()里也说过这个
$slice$sort,老师当时没讲,用法和$each类似,$bit,没讲
学完了这些,可以看出update其实是对三种类型进行更新 a:b a:[b] a:{a:b} 如果是a:[{a:b}],就将12两种类型复合起来,先找到建(例如age),才能改值
至此update结束
collection对象提供了还save()方法来实现插入和更新 //不重要
save的参数和insert一样,一个文档,它把一个新文档插入当前的集合,如果文档不存在就插入,存在就更新,语法和insert一样
最后说说删除
collection对象提供了两种删除
remove()和drop()
drop()和前面的dropDatabase()一样,直接删对象指向的内存,所以用了他集合就没了,索引什么也没了
remove(query,justone)
query说多少遍了不说了
justone和单词意思一样,删一个还是删全部,默认false删全部 //这里怎么不考虑保护数据了。。
****************************************************************************
9章
讲了collection对象的三个方法
group()提供一种基本聚合,根据指定的字段将文档分组
aggregate()让你能够访问聚合流水线
mapReduce()提供映射-归并聚合功能
group(key,cond,initial,reduce,finalize,keyf)
group(键,query,对象,函数1,函数2,函数3)
其中键,对象,函数1为必选,
键:用来分组的键 格式为key:{键:1},可以有多个键//得到obj
对象:一个初始group对象,格式就是一个文档,最后输出的内容就是在它基础上的 //得到prev
函数1:固定的两个参数,一个指初始文档,一个指向刚刚创建的初始对象,加工原文档把结果给新对象,并返回这个对象 function(obj,prev)
函数2可以接受函数1返回的对象(俩obj不一样),加工它的值,给对象加入新的列,再返回一个对象 function(obj)函数1和函数2的对象都是直接输出的
query对结果集进行限制,用法和前面一样
函数3用来代替键,但函数3返回值必须是用来分组的键
这个方法是对原集合一个文档一个文档遍历的,所以函数里算法应该按照这个写
看着很复杂,来写一个简单的例子
数据
db.createCollection("test")
db.test.insert([{number:1,value:100},{number:1,value:200},{number:2,value:300},{number:3,value:400}])
操作
按number分组,统计一下value的和,再把结果合并
如果理解了上面说的,就可以看出这三个要求分别对应key,函数1,函数2
db.test.group({key:{:1},initial:{},reduce:function(obj,prev){},finalize:function(obj){}})先写出需要的格式,避免掉括号
db.test.group({key:{number:1},initial:{value:0},reduce:function(obj,prev){prev.value+=obj.value},finalize:function(obj){obj.count=obj.number+obj.value}})
能看出函数2操作的是函数1返回的结果,如果不需要对这个结果操作,那么省略函数2就行
aggregate(operator,[operator],[...])
[operatra]是一堆聚合运算符,有哪些最后会列出,太多了希望不考
其实比上面的简单,就是对原文档用聚合运算符多次加工
操作
输出前两个文档并根据value倒序排序
db.test.aggregate({$limit:2},{$sort:{value:-1}})
其中$group有自己一堆运算符,先写个例子
db.test.aggregate({$group:{_id:"$number"}}) _id必须写,主键,这里其实就是在根据主键分组
db.test.aggregate({$group:{_id:"$number",values:{$sum:"$value"}}}) 统计value
mapReduce(map,reduce,arguments)
mapReduce(函数1,函数2,输出类型)
三个参数都是必须的
函数1:使用emit(key,value)对原始集合每个文档都执行一次它生成一个键值对,值是数组形式,组成一堆对象返回 //function(){}
函数2;对函数1返回的每个对象都执行一次它,参数就是对象的键和值 //function(key,values){}
输出类型:是一个对象,用来指定输出到哪,一般就{out:{inline:1}},把返回值在shell里打印出来
这里函数是直接写的,不用像group作为键的值,所以要有return
固定格式
db.test.mapReduce(function(){emit(this.,this.)},function(key,values){},{out:{inline:1}})
操作
还是统计value
db.test.mapReduce(function(){emit(this.number,this.value)},function(key,values){b=0;for(i=0;i<values.length;i++){b=b+values[i]}result={number:key,value:b};return result;},{out:{inline:1}})
解释下第一个函数的结果
函数1对集合里每个文档获取你设置的key和value,如果key相同,就把value加到values数组里,emit(key,value)这个函数只能写两个参
运行完应该是三个对象{1:[100,200]}{2:300}{3:400} 1就是设置的this.number,[100,200]就是他的值
函数2就是把1传给key,把[100,200]传给values,参数知道了怎么操作随你
输出类型的可选参数
out:必选一般{out:{inline:1}}
query:和前面一样,对结果限制
sort:对结果排序
limit:限制返回条数
finalize:和group里一样
*********************************************************************************************
后面几章是java操作,按实验来复习
固定格式
Mongo mg=new Mongo("127.0.0.1:27017");
相当于实例化一个connection对象,参数是当时配的端口
DB db=mg.getDB("数据库")
用getDB(string)获取一个database对象,参数是数据库名
DBCollection test=db.getCollection("集合名")
用getCollection()获取一个collection对象
剩下的和shell里语法很像
比如
getDatabaseNames() 返回一个数组,元素是所有数据库名
getCollectionNames()和前面说的一样,返回的是一个所有集合名数组
db对象的 对应shell
getDatabaseNames(string) //show databases
dropDatabase() //dropDatabase()
addUser(string,char[]) //createUser()
authenticate(string,char[]) //auth()
removeUser(string) //dropUser()
createCollection(string,DBobject) //createCollection()
参数基本都一样
collection对象的
getCollectionNames(string) //show collections
find() //find()里的运算符是DBObject形式的一样的
findOne()
drop()
insert()
remove()
save()
update()
会这几个就行,和shell用法一样
下面说两个对象
DBObject
对应的格式{}
DBObject dbo=new BasicDBObject()
List<T>
对应的格式[T] T可以是各种格式
List<String> list=new ArrayList<String>()
利用它来构成需要的文档格式,作为参数给上面的方法
和find()方法返回的对象DBcursor
DBCursor cur=test.find() 来获得它
一样是那四个方法
count()
limit(int)
skip(int)
sort(DBObject orderBy)
这里给个例子,课后题p166和p186的
public class test {
public static void main(String[] args)throws MongoException, UnknownHostException{
Mongo mg =new Mongo("127.0.0.1:27017");
DB db =mg.getDB("words");
DBCollection users=db.getCollection("word_stats");
DBCursor cur=users.find();
DBObject dbs=new BasicDBObject();
dbs.put("_id", -1);
cur=cur.sort(dbs);
System.out.println("1:"+JSON.serialize(cur));
dbs.put("last", -1);
cur=cur.sort(dbs);
System.out.println("2:"+JSON.serialize(cur));//p166 1
DBObject dbs1=new BasicDBObject();
dbs1.put("$regex", "^a.*e$");
dbs.put("word",dbs1);
DBCursor cur1=users.find(dbs);
System.out.println("3:"+JSON.serialize(cur1));//p166 2
dbs1.put("$regex", "^n");
dbs.put("word",dbs1);
DBCursor cur2=users.find(dbs);
dbs.put("size", -1);
cur=cur.sort(dbs);
cur=cur.limit(5);
System.out.println("4:"+JSON.serialize(cur2));//p186 1
}}
JSON.serialize(cur2)是转化字符串的
到这里就复习完了
下面总结上面提到的方法和运算符,只写方法名,可以测试记住了没
shell基本命令
use
show dbs(databases也行)/collections/users
database对象
createUser() doc{user pwd roles}
auth() str用户 str密码
createCollection() str options
dropDatabase()
getCollectionNames()
dropUser() str用户
collection对象
aggregate()
count()
distinct() str列 query
drop()
find() query projection
findOne() query projection
group() db.test.group({key:{:1},initial:{},reduce:function(obj,prev){},finalize:function(obj){}})
insert() doc
mapReduce() mapReduce(function(){emit(this.,this.)},function(key,values){},{out:{inline:1}})
remove() query boolean
save() doc
update() query update boolean boolean
cursor对象
count()
limit() int
skip() int
sort() {str列:int}
query运算符
$gt/$gte
$in/$nin
$lt/$lte
$ne
$or/$and/$not
$exists
$regex
$size
$elemMatch/$all
update运算符
$inc
$rename
$set
$unset
$addToSet
$push/$pushAll
$pull/$pullAll
$each
$pop
聚合运算符
$project
$match
$limit
$skip
$group