[TOC]
# 文档
文档是mongoDB中数据的基本单元,类似关系数据库的行,
多个键值对有序地放置在一起便是文档。
MongoDB 中以文档的方式存取记录,如一条记录格式如下:
~~~
{ “username”:”Tom”, “age”:10 ,email:’xiaobai@sohu.com’,’sex’:男,键,值}
{ "username":"Tom" , "age" : "10" }
{“Username”:”Tom”,”age”:10}
{“Username”:”Tom” }
~~~
注意:
(1)以上是几个不同的文档,MongoDB区分大小写的数据类型,第一个age字段是数字类型,第二个age是字符串类型。
(2)每一个文档尺寸不能超过16M
# 集合
集合就是一组文档,多个文档组成一个集合,集合类似于 mysql里面的表 。
无模式是指,在同一个集合中可以包含不同格式的文档,如:
~~~
{ "Name" : "Mongodb" , "Type" : "Nosql" }
{ "UserName" : "Tom" , "age" : 20 , "Gender" : "male" }
~~~
以上两个文档可以放在同一个集合中。
在Mysql需要先建表再插入数据,
模式自由(schema-free):意思是集合里面没有行和列的概念,
注意:MongoDB中的集合不用创建、没有结构,所以可以放不同格式的文档。
# 数据库
多个集合可以组成数据库。一个mongoDB实例可以承载多个数据库,他们之间完全独立。
Mongodb中的数据库和Mysql中的数据库概念类似,只是**无需创建**。
一个数据库中可以有多个集合。
一个集合中可以有多个文档。
# 数据体系
![](https://box.kancloud.cn/b55cec89ea506e5dc0e860436fc89035_637x757.png)
# 入门语句
** 创建数据库**
如果该数据库不存在,则创建,如果该数据库存在,则是切换,如果创建了数据库,没有任何的操作,则会自动删除该数据库。
~~~
use app
~~~
**查看数据库**
~~~
show dns
~~~
**创建集合**
注意:mongodb里面的集合是隐式创建,就是无需创建,直接使用。
语法:`db.集合名.insert({})`该语法意思是,向集合里面,添加文档
![](https://box.kancloud.cn/67dd8c0ca1ea31ddda74e2be44260535_941x280.png)
**查看集合**
`show tables`
**查询集合里面的文档**
~~~
db.集合名.find() 查询所有
db.集合名.findOne() 查询第一个文档
~~~
**删除集合**
~~~
db.集合名.drop();
~~~
**删除数据库**
~~~
use 数据库
db.dropDatabase()
~~~
# 增删改查
## 增加
~~~
db.集合名.insert({k1:’v1’,k2:’v2’…..})
~~~
~~~
db.class1.insert({k1:'v1', k2:'v2'})
~~~
注意点:
(1)文档就是键值对,数据类型是BSON格式,支持的值更加丰富。
比如:`db.集合名.insert({name:’xiaobai’,spc:{weight:100,address:’guangzhou’}})`
(2)在添加的文档里面,都有一个’_id’的键,值为对象类型。
ObjectId类型:
每个文档都有一个`_id`字段,并且同一集合中的_id值唯一,该字段可
以是任意类型的数据,默认是一个ObjectId对象。
ObjectId对象对象数据组成:`时间戳 |机器码|PID|计数器 `
_id的键值我们可以自己输入,但是不能重复
注意:在插入数据的时候,如果_id的值重复则会报错。
![](https://box.kancloud.cn/efbf6596159e87f3c1d1c4197949f607_1049x240.png)
(3) 可以使用js代码来完成批量插入文档。
![](https://box.kancloud.cn/45038211d99ad8533f100248b1c856c2_820x192.png)
## 删除
语法:db.集合名.remove({条件})(不写条件删除所有的文档)
例1:删除 php 集合中年龄等于5的文档
~~~
db.user.remove({age:5})
~~~
## 更新文档
方法一,直接修改
语法:db.集合名.update({条件},{新的文档},是否新增,是否修改多条)
语法: db.集合.update(条件,新文档, 是否新增, 是否修改多条)
是否新增:如果值是1(true)则没有满足条件的则添加。
是否修改多条:若值是1(true),如果满足条件的有多个文档则都要修改,
案例1:在php集合里面,要修改age=4的文档名称为xiaosi
~~~
db.php.update({age:4},{name:’xiaosi’})
~~~
![](https://box.kancloud.cn/1113df7f0c56f14145efd213f9b5bcb2_1087x346.png)
注意;以上修改方式,会丢失其他的键值,因此不推荐使用
案例2:要修改age=3的文档名称为xiaosan,并且其他键值不能丢失
使用修改器
`$inc` : 加一个数字
`$set` : 修改某一个字段,如果该字段不存在就增这个字段
语法:`db.集合名.update({条件},{修改器名称:{修改的键:修改的新值}})`
~~~
db.user.update({age:3},{'$set':{name:'xiaosan'}})
~~~
案例3:要修改age=1的文档的年龄添加10岁
语法:`db.集合名.update({条件},{修改器名称:{修改的键:修改的新值}})`
~~~
db.user.update({age:1},{'$inc':{age:10}})
~~~
![](https://box.kancloud.cn/ce6939accee8051c2fe53d1414af6dca_1116x304.png)
## 查询文档
语法:`db.集合名.find({条件})`
案例1:取出php集合里面第一个文档
~~~
db.user.findOne();
~~~
案例2:取出php集合里面age=2的文档
~~~
db.user.find({age:2})
~~~
案例3:取出php集合里面age大于2的文档
~~~
db.user.find({age:{‘$gt’:2}})
~~~
案例4:取出php集合里面的文档,只显示name键
~~~
db.user.find({},{name:1})//1表示只显示name键值
~~~
注意:`db.php.find({},{age:0})//0表示除了age键值,其他的都显示。`
案例5:根据年龄的(降序|升序)来显示文档
~~~
db.集合名.find().sort({age:1})根据年龄升序
db.集合名.find().sort({age:-1})根据年龄降序
~~~
案例6:显示php集合中前3个文档。
~~~
db.user.find().limit(3)
~~~
案例7:显示php集合中第3个文档到第5个文档。
~~~
db.user.find().skip(2).limit(5) 相当于 mysql里面的 limit offset number
~~~
案例8:统计php集合中文档的个数
~~~
db.集合名.count():返回集合中有多少个文档。
~~~
## 常用操作符
~~~
$lt , $lte , $gt , $gte ( < , <= , > , >= ), $ne ( <> ) ,$in , $nin , $or , $not,
$mod (取模), $exists, $where
db.php.remove({age:{‘$gt’:8}})
~~~
# 权限
在mongodb里面的用户是属于数据库的,每个数据库有自己的管理员,管理员登录后,只能操作所属的数据库。
注意:一般在admin数据库中创建的用户授予超级管理员权限,登录后可以操作任何的数据库。
![](https://box.kancloud.cn/cb082ac178da3033195112b7da7b9ea2_1076x574.png)
## 创建超级管理员
注意:在开启权限管理控制时,一定先要创建一个超级管理员授予超级管理权限。
登录mongodb的客户端,使用如下命令
~~~
use admin
db.createUser({ user:'root', pwd:'123456', roles:[{role:'root',db:'admin'}] })
~~~
## 修改mongodb数据库配置文件
~~~
MongoDB\Server\4.0\bin
security:
authorization: enabled
~~~
![](https://box.kancloud.cn/b445c7e542f50a84e79ca63b22ba3775_677x211.png)
## 重启mongodb服务
连接数据库
如果没有输入密码,进入 MongoDB的客户端,进行操作,会报如下错误提示;
![](https://box.kancloud.cn/da9707e6ca1520ce78ad4ebb924b18f3_979x346.png)
本地连接:
~~~
mongo 数据库名称 -u 用户名 -p 密码
mongo admin -u 用户名 -p 密码
~~~
~~~
远程连接:mongo IP地址:端口/数据库名称 -u 用户名 -p 密码
~~~
## 给php创建个普通管理员
~~~
use php
db.createUser( { user: "phpadmin", pwd: "123456", roles: [ { role: "dbOwner", db: "php" } ] } )
~~~
登录操作
![](https://box.kancloud.cn/87637169b77a6248d61b6dd6cd2825f4_1118x462.png)
## 常用命令
~~~
show users; #查看当前库下的用户
~~~
~~~
db.dropUser("eggadmin") #删除用户
db.updateUser( "admin",{pwd:"password"}); #修改用户密码
db.auth("admin","password"); #密码认证
~~~
![](https://box.kancloud.cn/c6a0cc42a0a6d3d8218700fc37a32674_1080x398.png)
# 数据库角色
(1)数据库用户角色:read、readWrite;
(2)数据库管理角色:dbAdmin、dbOwner、userAdmin;
(3)集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
(4)备份恢复角色:backup、restore;
(5)所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、 dbAdminAnyDatabase
(6)超级用户角色:root
# 索引
索引是对数据库表中一列或多列的值进行排序的一种结构,可以让我们查询数据库变得 更快。MongoDB 的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的查 询优化技巧。
## 普通单列索引
~~~
db.集合名.ensureIndex({name:1})
~~~
语法:
~~~
db.集合名.ensureIndex({键名:1}) 1是升续 -1是降续
~~~
## 多列索引(复合索引)
创建多列索引
~~~
db.集合名.ensureIndex({field1:1/-1, field2:1/-1});
~~~
对name和age 建立一个复合索引
可以使用db.集合名.getIndexes()查看创建的索引情况
![](https://box.kancloud.cn/1c018ec1a1541f3f504802e03ce64e3b_918x634.png)
该索引被创建后,基于 username 和 age 的查询将会用到该索引,或者是基于 username 的查询也会用到该索引,但是只是基于 age 的查询将不会用到该复合索引。因此可以说, 如果想用到复合索引,必须在查询条件中包含复合索引中的前 N 个索引列
## 子文档索引
语法:
~~~
db.集合名.ensureIndex({filed.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.集合名.ensureIndex({'spc.w':1})
~~~
![](https://box.kancloud.cn/68e3bb3106cbea51155dfa401c375f38_635x622.png)
## 唯一索引
~~~
db.集合名.ensureIndex({name:-1},{unique:true})
~~~
![](https://box.kancloud.cn/8943b889b208f4655d227362875cc5ae_1466x580.png)
![](https://box.kancloud.cn/1b9f8cd097520fe096a37ebe50fc4faf_742x143.png)
## 查看索引
常用命令:
(1)查看当前索引状态: `db.集合名.getIndexes(); `
(2)详情查看本次查询使用哪个索引和查询数据的状态信息。
explain executionStats 查询具体的执行 时间
~~~
db.tablename.find().explain( "executionStats" )
~~~
关注输出的如下数值:`explain.executionStats.executionTimeMillis`
![](https://box.kancloud.cn/59369e9b5a4491733aaa719c578f734b_819x383.png)
有索引时,查询时间;
![](https://box.kancloud.cn/3a119fda219febd9117e5366b7de4c77_664x407.png)
删除索引时查询时间
![](https://box.kancloud.cn/b48b230bfbab20a8d80dccf191057e00_801x504.png)
## 删除索引
删除单个索引
~~~
db.集合名.dropIndex({filed:1/-1});
~~~
删除所有索引
~~~
db.集合名.dropIndexes();
~~~
注意:在删除所有的索引时,主键索引会保留。
## 重建索引
一个表经过很多次修改后,导致表的文件产生空洞,索引文件也如此.
可以通过索引的重建,减少索引文件碎片,并提高索引的效率.
类似mysql中的`optimize table `
mysql里面使用optimize table语法:optimize table 表名
~~~
语法:db.集合名.reIndex()
~~~
## 索引使用注意
(1)创建索引的时候,注意1是正序创建索引 \-1是倒叙创建索引
(2)索引的创建在提高查询性能的同时会影响插入性能,对于经常查询少插入的文档可以考虑用索引
(3)复合索引要注意索引的先后顺序。
(4)每个键全建立索引不一定就能提高性能,索引不是万能的。
(5)在做排序工作的时候如果是超大数据量也可以考虑加上索引用来提高排序的性能。
# 数据导入导出
导入/导出可以操作的是本地的mongodb服务器,也可以是远程的,所以,都有如下通用选项。
利用mongoexport
~~~
-h host主机
--port 端口
-d 指明使用的库
-c 指明要导出的集合
-o 指明要导出的文件名
--csv指定导出的csv格式
-q 过滤导出
-f field1 field2 列名
-u username 用户名
-p password 密码
~~~
如下操作,
注意:如果端口是默认的可以不使用--port来指定端口。
比如我们要导出php库下面的Java集合,
~~~
E:\Program Files\MongoDB\Server\4.0\bin>mongoexport -h localhost -d php -c java -o e:/nihao.json -u phpadmin -p 123456
~~~
导出文件内容如下
![](https://box.kancloud.cn/a6168755fcf147306b747e611fba839d_860x88.png)
导入
使用mongoimport命令
~~~
-d 待导入的数据库
-c 待导入的集合(不存在会自己创建)
--type csv/json(默认)
--file 备份文件名称包含路径
~~~
~~~
例1: 导入json
./bin/mongoimport -h --port 端口号 -d test -c goods --file ./goodsall.json
例2: 导入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 --headline -f goods_id,goods_name --file ./goodsall.csv
案例:把刚才导出的nihao.json文件导入到php库里面的user集合里面。
E:\Program Files\MongoDB\Server\4.0\bin>mongoimport -h localhost -d php -c nihao --file e:/nihao.json -u phpadmin -p 123456
~~~
# 主从复制(读写分离)
主从复制是一个简单的数据库同步备份的集群技术。
1、原理图:
2、实现的注意点;
(1)在数据库集群中要明确的知道谁是主服务器,主服务器只有一台。
(2)从服务器要知道自己的数据源也就是对于的主服务是谁。
(3)--master用来确定主服务器,--slave和--source来控制从服务器。
![](https://box.kancloud.cn/0ddaf88effa10f9aebcfb285d021c4ca_612x512.png)
具体的配置步骤
(1)启动主服务器
~~~
--port --dbpath –logpath --master
~~~
![](https://box.kancloud.cn/63b422bf03df46cd7cf8f04ebd7b7c7d_1119x63.png)
(2)启动从服务器
~~~
--port –dbpath –logpath –slave –source 127.0.0.1:1111
~~~
![](https://box.kancloud.cn/a1f0ea88edabcb426e0cef94540f73ff_1120x63.png)
(3)客户端登陆到主服务器
添加一些数据,测试是否同步到从服务器
如下在主服务器里面,添加了一些文档
第一步:客户端登录到主服务器,添加一些文档
~~~
mongo localhost:1111
~~~
![](https://box.kancloud.cn/9999b0ab935073274a3eeccde311a042_939x260.png)
第二步:登陆到从服务器,查看是否有数据
~~~
mongo localhost:2222
~~~
如果有数据,则成功了
# php操作
## 插入数据
~~~
$manager = new MongoDB\Driver\Manager("mongodb://phpadmin:123456@localhost:27017/php");
//插入数据
//创建一个对象
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->insert(['name'=>'刘备','age'=>12,'email'=>'liubei@sohu.com']);
$bulk->insert(['name'=>'关羽','age'=>22,'email'=>'guanyu@sohu.com']);
$bulk->insert(['name'=>'张飞','age'=>18,'email'=>'zhangfei@sohu.com']);
$manager->executeBulkWrite('php.stu', $bulk);
echo 'ok';
~~~
## 查询数据
~~~
$filter = ['age'=>['$gt'=>16]];
$options = [
'projection'=>['_id'=>0],
'sort'=>['age'=>1]
];
$query = new MongoDB\Driver\Query($filter, $options);
//$query = new MongoDB\Driver\Query([],[]);
$data = $manager->executeQuery('php.stu', $query);
echo '<pre>';
foreach ($data as $key => $value) {
print_r($value);
}
~~~
## 更新数据
~~~
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->update(
['age' => 12],
['$set' => ['name' => '刘备被', 'email' => 'liubeibei@sohu.com']],
['multi' => false, 'upsert' => false]
);
$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
$result = $manager->executeBulkWrite('php.stu', $bulk, $writeConcern);
echo 'ok';
~~~
## 删除数据
~~~
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->delete(['age' => 22], ['limit' => 1]); // limit 为 1 时,删除第一条匹配数据
//$bulk->delete(['x' => 2], ['limit' => 0]); // limit 为 0 时,删除所有匹配数据
$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
$result = $manager->executeBulkWrite('php.stu', $bulk, $writeConcern);
var_dump($result);
~~~
# linux
linux系统安装mongodb
解压后,直接进入目录启动即可;在启动时要添加`--fork`参数,作为一个进程后台运行
![](https://box.kancloud.cn/0718d720eba766d823640eba29764235_575x61.png)
![](https://box.kancloud.cn/32589945323e8b42ad193f068479c009_906x262.png)
- 配置
- composer安装
- composer用法
- composer版本约束表达
- phpstorm
- sftp文件同步
- php类型约束
- laradock
- 配置文件缓存详解
- git
- 自定义函数
- 核心概念
- IOC
- 服务提供者
- Facade
- 契约
- 生命周期
- 路由
- 请求
- 命名路由
- 路由分组
- 资源路由
- 控制器路由
- 响应宏
- 响应
- Command
- 创建命令
- 定时任务
- console路由
- 执行用户自定义的定时任务
- artisan命令
- 中间件
- 创建中间件
- 使用中间件
- 前置和后置
- 详细介绍
- 访问次数限制
- 为 VerifyCsrfToken 添加过滤条件
- 单点登录
- 事件
- 创建
- ORM
- 简介
- DB类
- 配置
- CURD
- queryScope和setAttribute
- 查看sql执行过程
- 关联关系
- 一对一
- 一对多
- 多对多
- 远程关联
- 多态一对多
- 多态多对多
- 关联数据库的调用
- withDefault
- 跨模型更新时间戳
- withCount,withSum ,withAvg, withMax,withMin
- SQL常见操作
- 模型事件
- 模型事件详解
- 模型事件与 Observer
- deleted 事件未被触发
- model validation
- ORM/代码片段
- Repository模式
- 多重where语句
- 中间表类型转换
- Collection集合
- 新增的一些方法
- 常见用法
- 求和例子
- 机场登机例子
- 计算github活跃度
- 转化评论格式
- 计算营业额
- 创建lookup数组
- 重新组织出表和字段关系并且字段排序
- 重构循环
- 其他例子
- 其他问题一
- 去重
- 第二个数组按第一个数组的键值排序
- 搜索ES
- 安装
- 表单
- Request
- sessiom
- Response
- Input
- 表单验证
- 简介
- Validator
- Request类
- 接口中的表单验证
- Lumen 中自定义表单验证返回消息
- redis
- 广播事件
- 发布订阅
- 队列
- 守护进程
- redis队列的坑
- beanstalkd
- rabbitmq
- redis队列
- 日志模块
- 错误
- 日志详解
- 数据填充与迁移
- 生成数据
- 数据填充seed
- migrate
- 常见错误
- Blade模板
- 流程控制
- 子视图
- URL
- 代码片段
- Carbon时间类
- 一些用法
- 邮件
- 分页
- 加密解密
- 缓存
- 文件上传
- 优化
- 随记
- 嵌套评论
- 判断字符串是否是合法的 json 字符串
- 单元测试
- 计算出两个日期的diff
- 自定义一个类文件让composer加载
- 时间加减
- 对象数组互转方法
- 用户停留过久自动退出登录
- optional 辅助方法
- 文件下载
- Api
- Dingo api
- auth.basic
- api_token
- Jwt-Auth
- passport
- Auth
- Authentication 和 Authorization
- Auth Facade
- 授权策略
- Gates
- composer包
- debug包
- idehelp包
- image处理
- 验证码
- jq插件
- 第三方登录
- 第三方支付
- log显示包
- 微信包
- xss过滤
- Excel包
- MongoDB
- php操作
- 聚合查询
- 发送带附件邮件
- 中文转拼音包
- clockwork网页调试
- emoji表情
- symfony组件
- swooletw/laravel-swoole
- 常见问题
- 跨域问题
- Laravel队列优先级的一个坑
- cache:clear清除缓存问题
- .env无法读取
- 源码相关基础知识
- __set和__get
- 依赖注入、控制反转和依赖倒置原则
- 控制反转容器(Ioc Container)
- 深入服务容器
- call_user_func
- compact
- 中间件简易实现
- array_reduce
- 中间件实现代码
- Pipeline管道操作
- composer自动加载
- redis延时队列
- 了解laravel redis队列
- cli
- 源码解读
- Facade分析
- Facade源码分析
- IOC服务容器
- 中间件原理
- 依赖注入浅析
- 微信
- 微信公众号
- 常用接收消息
- 6大接收接口
- 常用被动回复消息
- 接口调用凭证
- 自定义菜单
- 新增素材
- 客服消息
- 二维码
- 微信语音
- LBS定位
- 网页授权
- JSSDK
- easywechat
- 小程序
- 小程序配置app.json