1. MongoDB 支持"字段索引,游标操作",其优势在于"查询功能比较强大",擅长"查询json数据",能存储"海量数据",但是"不支持事务"。
2. MongoDB应用范围和限制
缺点:不支持连表查询,不支持sql语句,不支持事务存储过程等,不适合存储数据间关系比较复杂的数据,主要当做一个数据仓库来使用。
适用于 :日志系统,股票数据。
不适用于 :电子商务系统等多表查询功能。
文档是 mongodb基本单元,类似关系数据的行。
多个键值对有序的放置一起便是文档
3.集合
集合就是一组文档 ,多个文档组成一格集合,集合类似于mysql的表
在不同一个集合可以包含不同格式的文档,如
{"name":"Mongodb","type":"Nosql"}
{"username":"tom","age":20 ,"gender":"male"}
以上两个文档可以放在同一个集合中,
模式自由:集合里面没有行和列的概念,
注意:Mongodb的集合不用创建,没有结构,所以可以放不同格式的文档。
增加文档
mongo入门命令mongo入门命令
1.1 :show dbs 查看当前的数据库
1.2 :use databaseName 选库
1.3 show collection 查看当前库下的collection
如何创建库?
Mongodb的库是隐式创建,你可以use 一个不存在的库
然后再该库下创建collection ,即可创建库
1.4 db.createCollection(‘collectionName’)
创建collection
collection 允许隐式创建
Db.collectionName.insert(document);
db.collectionName.drop()
删除collection
db.dropDatebase
删除datebase
./mongoexport -d bbs -c account -q {} -f name ,addr -- csv>account.csv -- 数据导出工具,导出为csv格式
./mongoexport -d bbs -c account -q {} -f name ,addr >account.json 导出为json格式
查询表达式:
1:最简单的查询表达式
{filed:value},是指查询filed列的值为value的文档
2:$ne ---》 !=查询表达式
3:$nin ---》 not in
4.$ all
5.$ exsits
语法:{filed:{$all[v1,v2...]}}
6:$nor
{$nor ,[条件1 ,条件2]}
是指所有条件都不满足文档为真返回
7.用正则表达式查询以若基亚开头的产品
例:db.goods.find({goods_name:/若基亚.*/}.{goods_name:1});
8:用$where 表达式来查询
例:db.goods.find({$where :'this.cat_id != 3 &&this.cat_id != 11'});
注意: 用$where查询时, mongodb是把bson结构的二进制数据转换为json结构的对象,
然后比较对象的属性是否满足表达式.速度较慢
Update时可用的操作符
例:->db.user.insert({name:'lisi',age:12,sex:'male',height:123,area:'haidian'});
>db.user.update({name:'lisi'},{$set:{area:'chaoyang'},$unset:{height:1},$inc:{age:1},$rename:{sex:'gender'}});
> db.user.find();
{ "_id" : ObjectId("51fc01c4f5de93e1f2856e33"), "age" : 13, "area" : "chaoyang", "gender" : "male", "name" : "lisi" }
$setOnInsert ->相当于mysql中的列的默认值
游标操作 cursor
游标是什么?
通俗的说,游标不是查询结果,而是查询的返回资源,或者接口.
通过这个接口,你可以逐条读取.
就像php中的fopen打开文件,得到一个资源一样, 通过资源,可以一行一行的读文件
声明游标:
var cursor = db.collectioName.find(query,projection);
Cursor.hasNext() ,判断游标是否已经取到尽头
cursor.next(),取出游标的下1个单元
用while来循环游标
> var mycursor = db.bar.find ({_id:{$lte:5}})
> while (mycursor.hasNext()){
printjson(mycursor.next());
}
例:
//声明游标
var cursor = db.goods.find();
//循环游标
for (var doc = true;cursor.hasnext(); ){printjson(cursor.next());}
也可以简写
for (var cursor = db.goods.find(),doc= true; cursor.hasnext();) {printjson(cursor.next());}
游标还有一个迭代函数,允许我们自定义回调函数来逐个处理每个单元
cursor.foreach(回调函数);
例:
> var gettitle = function(obj) {print(obj.goods_name)}
> var cursor = db.goods.find();
> cursor.forEach(gettitle);
游标在分页中的应用
比如查到10000行,跳过100页,取10行.
一般地,我们假设每页N行, 当前是page页
就需要跳过前 (page-1)*N 行, 再取N行, 在mysql中, limit offset,N来实现
在mongo中,用skip(), limit()函数来实现的
如 var mycursor = db.bar.find().skip(9995)
则是查询结果中,跳过9995行。
查询第901页
= db.bar.find().skip(9000).limit(10)
通过cursor一次性得到所有数据, 并返回数组.
例:
>var cursor = db.goods.find();
> printjson(cursor.toArray()); //看到所有行
> printjson(cursor.toArray()[2]); //看到第2行
> printjson(cursor.toArray()[3]); // 看到第三行
注意:不要随意使用toarray()
原因:会把所有行立即以对象形式组织在内存里。
可以在取出少数几行时用此功能
索引创建:
1.索引提高查询速度,降低写入速度
2.在mongodbz中,索引可以按照升序、降序来创建
3.默认是用btree来组织索引文件,2.4版本以后也允许 hash 来创建索引
查看查询计划:
db.find(query).explain();
"cursor":"basic cursor" -- 说明索引没有发挥作用
"nscannedObject" : 1000 -- 理论上要扫描1000行;
cursor" : "BtreeCursor sn_1", 用到的btree索引
常用命令:
查看当前索引状态: db.collection.getindexes();
创建普通的单列索引:db.collection.ensureindex({filed:1/-1}) 1是升序 2是降序
删除单个索引
db.collection.dropIndex({filed:1/-1});
一下删除所有索引
db.collection.dropindex();
创建多列索引:
db.colection.ensureindex({filed1:1/-1,filed2:2/-1});
创建子文档索引
db.coiiection.ensureindex({filed.subfiled:1/-1});
创建唯一索引
db.coiiection.ensureindex({filed.subfiled:1/-1},unqueen :true);
创建稀疏索引:
稀疏索引的特点------如果针对field做索引,针对不含field列的文档,将不建立索引.
与之相对,普通索引,会把该文档的field列的值认为NULL,并建索引.
适宜于: 小部分文档含有某列时.
db.collection.ensureIndex({field:1/-1},{sparse:true});
> db.tea.find();
{ "_id" : ObjectId("5275f99b87437c610023597b"), "email" : "a@163.com" }
{ "_id" : ObjectId("5275f99e87437c610023597c"), "email" : "b@163.com" }
{ "_id" : ObjectId("5275f9e887437c610023597e"), "email" : "c@163.com" }
{ "_id" : ObjectId("5275fa3887437c6100235980") }
如上内容,最后一行没有email列,
如果分别加普通索引,和稀疏索引,
对于最后一行的email分别当成null 和 忽略最后一行来处理.
根据{email:null}来查询,前者能查到,而稀疏索引查不到最后一行. //?
创建哈希索引(2.4新增的)
哈希索引速度比普通索引快,但是,无能对范围查询进行优化.
适宜于---随机性强的散列
db.collection.ensureIndex({file:’hashed’});
冲建索引
db.collection.reIndex()
Mongodb导出与导入
1: 导入/导出可以操作的是本地的mongodb服务器,也可以是远程的.
所以,都有如下通用选项:
-h host 主机
--port port 端口
-u username 用户名
-p passwd 密码
2: mongoexport 导出json格式的文件
问: 导出哪个库,哪张表,哪几列,哪几行?
-d 库名
-c 表名
-f field1,field2...列名
-q 查询条件
-o 导出的文件名
-- csv 导出csv格式(便于和传统数据库交换数据)
例:
[root@localhost mongodb]# ./bin/mongoexport -d test -c news -o test.json
connected to: 127.0.0.1
exported 3 records
[root@localhost mongodb]# ls
bin dump GNU-AGPL-3.0 README test.json THIRD-PARTY-NOTICES
[root@localhost mongodb]# more test.json
{ "_id" : { "$oid" : "51fc59c9fecc28d8316cfc03" }, "title" : "aaaa" }
{ "_id" : { "$oid" : "51fcaa3c5eed52c903a91837" }, "title" : "today is sataday" }
{ "_id" : { "$oid" : "51fcaa445eed52c903a91838" }, "title" : "ok now" }
例2: 只导出goods_id,goods_name列
./bin/mongoexport -d test -c goods -f goods_id,goods_name -o goods.json
例3: 只导出价格低于1000元的行
./bin/mongoexport -d test -c goods -f goods_id,goods_name,shop_price -q ‘{shop_price:{$lt:200}}’ -o goods.json //? 为什么$lt不是1000,没有懂
注: _id列总是导出
Mongoimport 导入
-d 待导入的数据库
-c 待导入的表(不存在会自己创建)
--type csv/json(默认)
--file 备份文件路径
例1: 导入json
./bin/mongoimport -d test -c goods --file ./goodsall.json
例2: 导入csv
./bin/mongoimport -d test -c goods --type csv -f goods_id,goods_name --file ./goodsall.csv
./bin/mongoimport -d test -c goods --type csv --headline -f goods_id,goods_name --file ./goodsall.csv
mongodump 导出二进制bson结构的数据及其索引信息
-d 库名
-c 表名
-f field1,field2...列名
例:
mongodum -d test [-c 表名] 默认是导出到mongo下的dump目录
规律:
1:导出的文件放在以database命名的目录下
2: 每个表导出2个文件,分别是bson结构的数据文件, json的索引信息
3: 如果不声明表名, 导出所有的表
mongorestore 导入二进制文件
例:
./bin/mongorestore -d test --directoryperdb dump/test/ (mongodump时的备份目录)
二进制备份,不仅可以备份数据,还可以备份索引,
备份数据比较小.
mongodb的用户管理
注意:
A)在mongodb中,有一个admin数据库, 牵涉到服务器配置层面的操作,需要先切换到admin数据.
即 use admin , -->相当于进入超级用户管理模式.
B)mongo的用户是以数据库为单位来建立的, 每个数据库有自己的管理员.
C) 我们在设置用户时,需要先在admin数据库下建立管理员---这个管理员登陆后,相当于超级管理员.
0: 查看用户
1: 添加用户
命令:db.addUser();
简单参数: db.addUser(用户名,密码,是否只读)
注意: 添加用户后,我们再次退出并登陆,发现依然可以直接读数据库?
原因: mongodb服务器启动时, 默认不是需要认证的.
要让用户生效, 需要启动服务器时,就指定 --auth 选项.
这样, 操作时,就需要认证了
例:
1: 添加用户
> use admin
> db.addUser(‘sa’,’sa’,false);
2: 认证
> use test
> db.auth(用户名,密码);
3: 修改用户密码
> use test
> db.changeUserPassword(用户名, 新密码);
> db.changeuserpassword(用户名,新密码);
4:删除用户
> use test
> db.removeUser(用户名);
注: 如果需要给用户添加更多的权限,可以用json结构来传递用户参数
例:
> use test
>db.addUser({user:'guan',pwd:'111111',roles:['readWrite,dbAdmin']});
replication set复制集
replicattion set 多台服务器维护相同的数据副本,提高服务器的可用性.
Replication set 设置全过程
0:创建目录
mkdir -p /data/r0 /data/r1 /data/r2
1:启动3个实例,且声明实例属于某复制集
/bin/mongod --port 27017 --dbpath /data/r0 --smallfiles --replSet rsa --fork --logpath /var/log/mongo17.log
./bin/mongod --port 27018 --dbpath /data/r1 --smallfiles --replSet rsa --fork --logpath /var/log/mongo18.log
./bin/mongod --port 27019 --dbpath /data/r2 --smallfiles --replSet rsa --fork --logpath /var/log/mongo19.log
2:配置
rsconf = {
_id:'rsa',
members:
[
{_id:0,
host:'192.168.1.201:27017'
}
]
}
3: 根据配置做初始化
rs.initiate(rsconf);
4: 添加节点
rs.add('192.168.1.201:27018');
rs.add('192.168.1.201:27019');
5:查看状态
rs.status();
6:删除节点
rs.remove('192.168.1.201:27019');
7.
7:主节点插入数据
>use test
>db.user.insert({uid:1,name:'lily'});
8:连接secondary查询同步情况
rsa:SECONDARY> show tables;
Sat Aug 17 16:03:55.786 JavaScript execution failed: error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
8.1 出现上述错误,是因为slave默认不许读写
>rs.slaveOk();
>show tables
#看到与primary 一致的数据 //?
分片