四、增删改查操作
1、添加文档
db.集合名.insert({k1:v1,k2:v2...})
:向当前数据库的该集合下添加文档
我们在添加文档的时候有如下注意点:
a) 文档就是键值对,数据类型是 BSON
格式,支持的值更加丰富。 BSON
是 JSON
的扩展,新增了诸如日期,浮点等 JSON
不支持的数据类型。
b) 在添加的文档里面,都有一个 '_id'
的键,值为对象类型 ObjectID
,在这里,我们解释下 ObjectID
类型:
每个文档都有一个 _id
字段,并且同一集合中的 _id
值唯一,该字段可以是任意类型的数据,默认是一个 ObjectID
对象。
ObjectID
对象数据组成:时间戳|机器码|PID|计数器
_id
的键值我们可以自己输入,但是不能重复,但要注意的一点是在插入数据的时候,如果 _id
的值重复则会报错
c) 可以使用 js
代码来完成批量插入文档
example:
> for(var i=1;i<=10;i++){ ... db.php.insert({'name':'xiaobai'+i,'age':i,'email':'xiaobai'+i+'@gmail.com'}) ... } WriteResult({ "nInserted" : 1 }) > db.php.find() { "_id" : ObjectId("5b931b74a39e4f4842ba36b3"), "name" : "xiaoming", "age" : 20, "email" : "xiaoming@gmail.com" } { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b5"), "name" : "xiaobai1", "age" : 1, "email" : "xiaobai1@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b6"), "name" : "xiaobai2", "age" : 2, "email" : "xiaobai2@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b7"), "name" : "xiaobai3", "age" : 3, "email" : "xiaobai3@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b8"), "name" : "xiaobai4", "age" : 4, "email" : "xiaobai4@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b9"), "name" : "xiaobai5", "age" : 5, "email" : "xiaobai5@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaobai6", "age" : 6, "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 10, "email" : "xiaobai10@gmail.com" }
2、删除文档
db.集合名.remove{(条件)}
:删除当前数据库下指定集合中满足条件的文档(不写条件则删除所有的文档)
example:
> db.php.remove({age:20}) WriteResult({ "nRemoved" : 1 }) > db.php.remove({age:{'$lt':6}}) WriteResult({ "nRemoved" : 5 }) > db.php.find() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaobai6", "age" : 6, "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 10, "email" : "xiaobai10@gmail.com" }
这里我们在删除 php
集合中年龄小于6的文档时,我们使用了操作符来完成。
比较运算符
操作符 | 效果 |
$gt |
大于 |
$lt |
小于 |
$gte |
大于等于 |
$lte |
小于等于 |
$exists |
存在与否 |
$in |
包含 |
$ne |
不等于 |
$nin |
不包含 |
逻辑运算符
操作符 | 效果 |
$exists |
存在与否 |
$or |
或者 |
$and |
并且 |
$not |
不存在 |
$mod |
求模 |
$where |
位置 |
特别的 $exists: true 表示字段存在
排序 sort
操作 | 效果 |
$asc |
升序 |
$desc |
降序 |
3、更新文档
更新文档有两种方式进行修改
方法一、直接修改
db.集合名.update({条件},{新的文档})
:修改当前数据库下指定集合中满足条件的文档信息
example:
> db.php.find() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" } > db.php.update({age:18},{name:'xiaobai5'}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.php.find() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }
db.集合.update(条件,新文档,是否新增,是否修改多条)
:修改当前数据库下指定集合中满足条件的文档信息
- 是否新增:如果值是1(true)则没有满足条件的 则添加
- 是否修改多条:若值是1(true),如果满足条件的有多个文档 则都要修改
example:
> db.php.update({age:10},{name:'xiaoli'},true,true) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 9, "errmsg" : "multi update only works with $ operators" } })
方法二、使用修改器
example:
我们要修改 age=6
的文档名称为 xiaosan
,并且其他键值不能丢失
我们可以使用修改器
$inc
:加上一个数字$set
:修改某一个字段,如果该字段不存在就增这个字段
语法:db.集合名.update({条件},{修改器名称:{修改的键:修改的新值}})
> db.php.update({age:6},{'$set':{name:'xiaosan'}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
那如果我们要修改 age=10
的文档的年龄增加十岁,我们可以这样做:
> db.php.update({age:10},{$inc:{age:10}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
4、查询文档
语法: db.集合名.find({条件})
example:
取出 php
集合里面的第一个文档
> db.php.findOne() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }
取出 php
集合里面 age=6
的文档
> db.php.find({age:6}) { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "age" : 6, "email" : "xiaobai6@gmail.com" }
取出 php
集合里面 age>8
的文档
> db.php.find({age:{'$gt':8}}) { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 20, "email" : "xiaobai10@gmail.com" }
取出 php
集合里面的文档,只显示 name
键
> db.php.find({},{age:1})//1表示只显示age键值 { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4") } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "age" : 6 } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "age" : 7 } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "age" : 8 } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "age" : 9 } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "age" : 20 } > db.php.find({},{age:0})//1表示除了显示age键值,其他的都显示 { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "email" : "xiaobai10@gmail.com" }
根据年龄的(降序|升序)来显示文档
db.集合名.find().sort({age:1})根据年龄升序 db.集合名.find().sort({age:0})根据年龄降序
显示 php
集合中的前三个文档
> db.php.find().limit(3) { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "age" : 6, "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" }
显示 php
集合中的第三个文档到第五个文档
> db.php.find().skip(2).limit(3) { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" }
统计 php
集合中文档的个数
db.集合名.count():返回集合中有多少个文档
五、用户管理(权限控制)
1、权限概述
在 MongoDB
里面的用户是属于数据库的,每个数据库都有自己的管理员。管理员登录后,只能操作所属的数据库。注意:在 admin
的数据库中创建的用户是超级管理员,登陆后可以操作任何的数据库
2、创建用户
(1) 选择数据库
use 数据库的名称
(2) 添加用户
db.createUser(用户名,密码,是否只读)
第三个参数"是否只读"默认是 false
,创建的用户可以执行读写,如果是 true
,则创建的用户只能查询,不能修改。
注意点:在创建用户之前,必须先创建一个超级管理员
example:
> use admin switched to db admin > db.createUser({user:'user', ... pwd:'passwd', ... roles:[ ... {role:'userAdminAnyDatabase', db:'admin'} ... ] ... }) Successfully added user: { "user" : "user", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
3、验证权限(用户登录)
在添加完成管理员之后,我们做如下操作:
(1) 如果你是安装成windows服务的方式安装的,则卸载服务,在安装时添加一个 -auth
选项,auth
表示要开启权限认证
(2) 如果你是直接启动的方式,则停止服务,重新启动,在启动时也要添加 --auth
选项,auth
表示要开启权限认证
如果没有通过权限验证,直接操作数据库,则报如下错误提示:
error: { "$err" : "unauthorized db:test lock type:-1 client:127.0.0.1", "code" : 10057 }
如何通过权限验证
- 选择数据库
- 执行
db.auth
(用户名,密码)
4、删除用户和修改密码
注意:创建的用户名和密码是存储在各自数据库里面的 system.users
集合里面的。想要删除用户,则直接删除 system.users
集合里面的文档即可
5、总结说明
a) 非 admin
数据库的用户不能使用数据库命令,比如 show dbs
等
(b) admin
数据库中的用户被视为超级用户(即管理员),在认证之后,管理员可以读写所有数据库,执行特定的管理命令。
(c) 在开启安全检查之前,一定要至少有个管理员账户。
(d) 数据库的用户账号以文档的形式存储在 system.users
集合里面。可以在 system.users
集合中删除用户账号文档,就可以删除用户。
六、MongoDB中的索引
1、普通单列索引
我们用如下代码来测试:
for(var i=0;i<200000;i++){ db.java.insert({name:'xiao'+i,age:i}) }
第一、我们先检验一下查询性能
var start=new Date() db.java.find({name:'xiao156789'}) var end=new Date() end-start 17510
第二、为 name
创建索引
> db.java.ensureIndex({name:1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
第三、再执行第一部分代码可以看出有数量级的性能提升
语法:db.集合名.ensureIndex({键名:1})
:1是升序,-1是降序
2、多列索引(复合索引)
创建多列索引
语法:db.集合名.ensureIndex({field1:1/-1,field2:1/-1})
对 name
和 age
建立一个复合索引,可以使用 db.集合名.getIndexes()
查看创建的索引情况
3、子文档索引
语法: db.集合名.ensureIndex({field.subfield:1/-1})
如下文档可以建立子文档索引
{name:'诺基亚手机1',price:12.34,spc:{weight:100,area:'纽约'}} {name:'诺基亚手机2',price:42.34,spc:{weight:200,area:'伦敦'}}
比如要查询 weight=100
的文档
db.goods.find({'spc.weight':100})
根据当前案例,我们建立子文档索引
db.net.ensureIndex({'spc.w':1})
4、唯一索引
语法: db.集合名.ensureIndex({name:-1},{unique:true})
5、查看索引
(1) 查看当前索引状态: db.集合名.getIndexes()
(2) 详情查看本次查询使用哪个索引和查询数据的状态信息: db.集合名.find({name:''xiao}).explain()
6、删除索引
删除单个索引: db.集合名.dropIndex({filed:1/-1})
删除所有索引: db.集合名.dropIndexes()
7、重建索引
一个表经过很多次修改后,导致表的文件产生空洞,索引文件也如此,可以通过索引的重建,减少索引文件碎片,并提高索引的效率,类似 mysql
中的 optimize table
。
mysql
里面使用 optimize table
语法: optimize table
表名
语法: db.集合名.reIndex()
8、索引使用注意事项
(1) 创建索引的时候,注意1是正序创建索引,-1是倒序创建索引
(2) 索引的创建在提高查询性能的同时会影响插入性能,对于经常查询少插入
(3) 复合索引要注意索引的先后顺序
(4) 每个键全建立索引不一定就能提高性能,索引不是万能的。
(5) 在做排序工作的时候如果是超大数据量也可以考虑加上索引用来提高排序的性能。
八、MongoDB中的数据导出与导出
利用mongoexport
- -h host主机
- -port 端口
- -d 指明使用的库
- -o 指明要导出的文件名
- -csv 指定导出的csv格式
- -q 过滤导出
- -f field1 field2 列名
- -u username 用户名
- -p password 密码
注意:在使用用户名和密码是超级管理员的时候,如果端口是默认的可以不使用-port来指定端口
(2) 导入数据
- -d 待导入的数据库
- -c 待导入的集合(不存在会自己创建)
- -type csv/json(默认)
- -file 备份文件路径
例如:导入json
./bin/mongoimport -h -port 端口号 -d test -c goods -file ./goodsall.json
导入csv
./bin/mongoimport -h -port 端口号 -d test -c goods -type csv -f goods.id,goods.name -file ./goodsall.csv ./bin/mongoimport -h -port 端口号 -d test -c goods -type csv -f -headline -f goods.id,goods.name -file ./goodsall.csv
九、主从复制(读写分离)
主从复制是一个简单的数据库同步备份的集群技术,至少两台数据库服务器,可以分别设置主服务器和从服务器,对主服务器的任何操作都会同步到从服务器上。
实现的注意点
1、在数据库集群中要明确的知道谁是主服务器,主服务器只有一台
2、从服务器要知道自己的数据源 也就是对应的主服务是谁
3、--master用来确定主服务器 --slave和--source来控制从服务器
配置步骤
(1) 启动主服务器
(2) 启动从服务器
(3) 客户端登录到主服务器
添加一些数据,测试是否同步到从服务器,在主服务器里面,添加了一些文档:
第一步,客户端登录到主服务器,添加一些文档
第二步,登录到从服务器,查看是否有数据,如果有数据,则成功了!
十、php操作MongoDB
1、安装扩展
注意:扩展文件,下载合适的php_mongodb.dll文件
1) php的版本
2) 是否是线程安全的thread safe(ts)
3) 是vc几的
4) php是32位的还是64位的
步骤
1) 把对应的扩展,拷贝到PHP的安装目录里面的ext目录下面,注意:拷贝后改名为php_mongo.dll,方便管理
2) 打开php.ini文件,引入该扩展
extension=php_mongo.dll
3) 重启Apache,使用phpinfo()函数测试
2、入门使用
1) 连接mongodb服务器
$m=new MongoClient("mongodb://root:root@localhost:8888/admin"); $db=$m->selectDb("stu");//选择数据库
2) 增删改查用法
增删改查
注意,在命令行里面的"." 变成了"->","{}"变成了数组
a) 添加一个文档
$db->php->insert(array('name'=>'李元霸','age'=>12));
b) 查询文档
$data=$db->php->find();
查询年龄等于9的文档:
$data=$db->php->find(array('age'=>9));
查询年龄大于9的文档:
//db.php.find({age:{'$gt':9}}) $data=$db->php->find(array('age'=>array('$gt':9)));
根据年龄降序显示:
$data=$db->php->find()->sort(array('age'=>1)); foreach($data as $v){ echo $v['name'].'----'.$v['age'].'--'.$v['email'].''; }
c) 修改文档,我们直接使用修改器来完成
把年龄等于8的名称改名为李白:
//db.php.update({age:8},{'$set':{'name':'李白'}}) $db->php->update(array('age'=>8),array('$set'=>array('name'=>'李白'));
d) 删除文档
比如删除年龄等于10的文档:
//db.php.remove({age:10}) $db->php->remove(array('age'=>10)) $data=$db->php->find() foreach($data as $v){ echo $v['name'].'----'.$v['age'].'--'.$v['email'].''; }
3) 把mysql表里面的数据存储到mongodb里面
selectDb("stu");//选择数据库 //从mysql里面取出数据 $conn=mysql_connect('localhost','root','root'); mysql_query('use shop'); mysql_query('set names utf8'); $sql="select * from goods"; $res=mysql_query($sql); while($row=mysql_fetch_assoc($res)){ $db->goods->insert($row); } echo 'ok';