同福

MongoDB安装笔记【20201002】

介绍

介绍

MongoDB是一个文档数据库引擎,文档数据库和MySQL这种关系型数据库是不一样的设计,文档数据库和Redis这种Key-Value数据库也有很大差别。不过文档数据库和Key-Value数据库都属于NoSQL型的数据库,也就是说MongoDB也是不支持SQL语句的。

MongoDB相对于MySQL数据库来说有一项独有的非常强大的特点,就是MongoDB的数据表结构是自由的,可以针对每一个文档(一行数据)定义不同的字段。

MongoDB的文档的存储格式是主流的数据个数JSON,JSON数据是可以设计成一个树状结构的,可以将一个对象的属性以及子属性、孙属性甚至更具体的属性保存到一个JSON数据当中,而MongoDB的一个文档就可以保存它,而无需事先设计好数据表结构来适应这种对象。

基本信息

安装环境

CentOS:CentOS Linux release 7.6.1810 (Core)
Linux:Linux version 3.10.0-1062.el7.x86_64
GCC:gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)

软件版本

mongodb-linux-x86_64-rhel70-4.2.2.tgz

准备工作

本地化

如果是新环境,我们需要设置时区以保证时间显示正确

timedatectl set-timezone Asia/Shanghai

安装wget

如果环境里没有wget,通过yum安装一下

yum -y install wget

安装依赖包

yum -y install libaio numactl-libs

建立环境根目录

mkdir -p /tongfu.net/env/

建立安装包目录并进入

mkdir /packages
cd /packages

安装MongoDB 4.2

官网下载

从官网下载

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.2.tgz

网盘下载

如果官网下载太慢,可以从网盘下载

链接: https://pan.baidu.com/s/1KjL759qM81Ix_ZRZZxdepg 提取码: yvpi

安装

设置mongo环境变量

[root@tfdev env]# vi /etc/profile

export MONGODB_HOME=/tongfu.net/env/mongodb-4.2.2
export PATH=$MONGODB_HOME/bin:$PATH

立即启用环境变量

source /etc/profile

创建用户

useradd mongo

解压缩

tar -xzvf mongodb-linux-x86_64-rhel70-4.2.2.tgz -C /tongfu.net/env/
cd /tongfu.net/env/
mv mongodb-linux-x86_64-rhel70-4.2.2/ mongodb-4.2.2

建立数据目录

mkdir /tongfu.net/env/mongodb-4.2.2/conf
mkdir /tongfu.net/env/mongodb-4.2.2/data
mkdir /tongfu.net/env/mongodb-4.2.2/logs

建立配置文件

[root@tfdev env]# vi /tongfu.net/env/mongodb-4.2.2/conf/mongodb.conf

dbpath = /tongfu.net/env/mongodb-4.2.2/data/
logpath = /tongfu.net/env/mongodb-4.2.2/logs/mongodb.log
bind_ip = 0.0.0.0
wiredTigerCacheSizeGB = 2
auth = true
journal = true

设置权限

chown mongo.mongo -R /tongfu.net/env/mongodb-4.2.2/

自动启动

添加自动启动脚本

[root@tfdev env]# cat > /lib/systemd/system/mongod.service <<EOF
[Unit]
Description=mongod
After=network.target
 
[Service]
Type=forking
User=mongo
Group=mongo
ExecStart=/tongfu.net/env/mongodb-4.2.2/bin/mongod -f /tongfu.net/env/mongodb-4.2.2/conf/mongodb.conf --fork
ExecStop=/tongfu.net/env/mongodb-4.2.2/bin/mongod -f /tongfu.net/env/mongodb-4.2.2/conf/mongodb.conf --shutdown
PrivateTmp=true
 
[Install]
WantedBy=multi-user.target
EOF

运行自动启动

systemctl enable mongod # 设置自动启动 

systemctl start mongod # 启动服务 

systemctl stop mongod # 停止服务 

systemctl restart mongod # 重启服务

服务命令添加到系统目录

ln -s /tongfu.net/env/mongodb-4.2.2/bin/mongo /usr/bin/

连接数据库admin

首次登录,无需用户名和密码,直接连接 admin 数据库

/tongfu.net/env/mongodb-4.2.2/bin/mongo 127.0.0.1:27017/admin

创建超级用户

设置超级用户root

db.createUser(
	{
		user:"root",
		pwd:"abcdef",
		roles: [
			{ role:"readWriteAnyDatabase", db:"admin" },
			{ role:"userAdminAnyDatabase", db:"admin" },
			{ role:"dbAdminAnyDatabase", db:"admin" }
		]
	}
);

重新连接数据库admin

使用超级用户root连接数据库admin

/tongfu.net/env/mongodb-4.2.2/bin/mongo -uroot -pabcdef 127.0.0.1:27017/admin

创建数据库

创建数据 field

use field

插入一条数据到表 field

db.field.insert({"id":1,"uName":"萝卜","age":21})

查询表 field 的所有数据

db.field.find()

插入一条数据到表 logs

db.logs.insert({"id":1,"event":"create record"})

查看所有数据库

show dbs

查看所有数据表(集合)

show collections

总结

  1. mongodb的数据库其实就是一个根文件夹

  2. mongodb的数据表就是根文件夹下的子文件夹

  3. mongodb的数据行就是子文件夹下的一个文件,多行数据就是多个文件

  4. mongodb的数据没有字段概念,就是一个大JSON数据结构,也就是一个字符串

  5. mongodb提供了很多方法去查询这些数据

数据导出/导入

导出数据

通过下面的命令导出整个数据库

mongodump -u $user -p $passwd -h $host --port $port -d $dbname -o $backupDir

导入数据

通过下面的命令恢复整个数据库

注意:备份出来的目录下面会有备份的数据库的文件夹,要指定到这一级才行

mongorestore -u $user -p $passwd -h $host --port $port -d $dbname $backupDir/$dbname

MongoDB用户管理

创建用户

使用无认证模式启动mongod

选择admin数据库

use admin

创建root用户

db.createUser(
    {
      user:"root",
      pwd:"123456",
      roles: [ { role:"userAdminAnyDatabase", db:"admin" },{ role:"dbAdminAnyDatabase", db:"admin" },{ role:"readWriteAnyDatabase", db:"admin" } ]
    }
)

使用认证模式重启mongod

用root登录到admin

/tongfu.net/env/mongodb-3.6.2/bin/mongo -u root -p 123456 admin

选择test数据库

use test

为test库创建用户test

db.createUser(
    {
      user:"test",
      pwd:"123456",
      roles: [ { role:"dbAdmin", db:"test" },{ role:"readWrite", db:"test" } ]
    }
)

退出root登录

使用test登录到test

/tongfu.net/env/mongodb-3.6.2/bin/mongo -u test -p 123456 test

修改用户

用root登录到admin

/tongfu.net/env/mongodb-3.6.2/bin/mongo -u root -p 123456 admin

选择test数据库

use test

修改密码

db.updateUser(
    'test',
    {
      pwd:"654321"
    }
)

删除用户

用root登录到admin

/tongfu.net/env/mongodb-3.6.2/bin/mongo -u root -p 123456 admin

选择test数据库

use test

删除test(居然可以删自己!!!)

db.dropUser('test')

查看用户列表

1、登录到admin数据库

2、选择admin数据库

use admin

3、查看用户列表

db.system.users.find()

总结

  1. 创建、修改、删除用户必须有权限

  2. 用户可以删除自己!!!

  3. 调整哪个库的用户表要先选择哪个库

  4. 查看用户列表必须到admin库下操作

  5. 建议弄一个root超级用户,然后给每个库一个独立账号

用户角色

Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root:只在admin数据库中可用。超级账号,超级权限

坑爹一

认证失败的解决方法

刚刚安装好的环境,使用MongoClient去连接服务器,结果死活报认证错误。
明明是正确的用户名,密码,数据啊~~

从网上查发现旧版本的mongo扩展用的是 MONGODB-CR认证方式。
而最新版的MongoDB服务器得用Scram-SHA-1认证方式

好吧,升级mongo扩展到1.6.13,解决了~~

TFAPI操作MongoDB的方法

示例

// 引入adodbj包,adodbj为JSON行数据库的统称
linking('dbj.adodbj');
 
// 连接MongoDB服务器
$myDbjObj = new adodbj("driver=mongo;server=localhost;port=27017;uid=field;pwd=abcdef;database=field;charset=utf-8;");
// 查看数据库列表(需要有访问admin的权限)
//$dbArr = $myDbjObj->getDbs(); var_dump($dbArr);
$condArr = array(
        'domainName'=>array('$regex'=>"ali213" ,'$options'=>"iq"),
    );
// 查询数据数量
$ret = $myDbjObj->count("urls", $condArr); $this->showRet($ret, "count");
// 查询所有数据
$ret = $myDbjObj->search("urls", $condArr, 0, 10, array('_id'=>-1, 'domainName'=>-1));
foreach ($ret as $itm){
    $this->showRet($itm, "search");
}
// 添加记录,ID为1
$ret = $myDbjObj->add("urls", array('domainName'=>"www.ali213.net ". rand(1111, 9999) ), 1); $this->showRet($ret, "add");
// 手动添加1000条数据,ID为1+$i
for($i=0;$i<1000;$i++){
    $ret = $myDbjObj->mod("urls", $i+1, array('domainName'=>"www.ali213.net ". rand(1111, 9999), 'idx'=>rand(111, 999) ) ); ///$this->showRet($ret, "mod");
}
// 通过mod修改一条数据,ID为1
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('weight'=>33)); $this->showRet($ret, "modRange");
// 查看数据,ID为1
$ret = $myDbjObj->get("urls", 1); $this->showRet($ret, "get");
// 查看索引
$ret = $myDbjObj->getIndexes("urls"); $this->showRet($ret, "get indexes");
// 创建索引
$ret = $myDbjObj->createIndex("urls", array('domainName'=>1)); $this->showRet($ret, "create index");
// 删除索引
$ret = $myDbjObj->dropIndex("urls", array('domainName'=>1)); $this->showRet($ret, "drop index");
// 清除所有索引
$ret = $myDbjObj->dropIndexes("urls"); $this->showRet($ret, "drop indexes");

TFAPI操作MongoDB的方法(新)

概念

新版本的MongoDB驱动完全变了样,一般情况下我们还是喜欢用旧版本的对象
怎么办呢?
没有关系,官方提供了一个第三方PHP库,封装了新版本的PHP扩展的对象,和老版本的对象及其相似
我们TFAPI也将这个库引入了进来,放到了 driver/mongo 下

使用技巧

// 引入adodbj包,adodbj为JSON行数据库的统称
linking('dbj.adodbj');
 
// 连接MongoDB服务器,注意:这里的 driver 是 mongo2 不是 mongo 了!!
$myDbjObj = new adodbj("driver=mongo2;server=localhost;port=27017;uid=field;pwd=abcdef;database=field;charset=utf-8;");
// 查看数据库列表(需要有访问admin的权限)
//$dbArr = $myDbjObj->getDbs(); var_dump($dbArr);
$condArr = array(
        'domainName'=>array('$regex'=>"ali213" ,'$options'=>"iq"),
    );
// 查询数据数量
$ret = $myDbjObj->count("urls", $condArr); $this->showRet($ret, "count");
// 查询所有数据
$ret = $myDbjObj->search("urls", $condArr, 0, 10, array('_id'=>-1, 'domainName'=>-1));
foreach ($ret as $itm){
    $this->showRet($itm, "search");
}
// 添加记录,ID为1
$ret = $myDbjObj->add("urls", array('domainName'=>"www.ali213.net ". rand(1111, 9999) ), 1); $this->showRet($ret, "add");
// 手动添加1000条数据,ID为1+$i
for($i=0;$i<1000;$i++){
    $ret = $myDbjObj->mod("urls", $i+1, array('domainName'=>"www.ali213.net ". rand(1111, 9999), 'idx'=>rand(111, 999) ) ); ///$this->showRet($ret, "mod");
}
// 通过mod修改一条数据,ID为1
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('weight'=>33)); $this->showRet($ret, "modRange");
// 查看数据,ID为1
$ret = $myDbjObj->get("urls", 1); $this->showRet($ret, "get");
// 查看索引
$ret = $myDbjObj->getIndexes("urls"); $this->showRet($ret, "get indexes");
// 创建索引,只能一个一个创建了
$ret = $myDbjObj->createIndex("urls", array('domainName'=>1)); $this->showRet($ret, "create index 1");
$ret = $myDbjObj->createIndex("urls", array('visits'=>2)); $this->showRet($ret, "create index 2");
// 删除索引,只能一个一个删除了
$ret = $myDbjObj->dropIndex("urls", 'domainName_1'); $this->showRet($ret, "drop index 1");
$ret = $myDbjObj->dropIndex("urls", 'visits_2'); $this->showRet($ret, "drop index 2");
// 清除所有索引
$ret = $myDbjObj->dropIndexes("urls"); $this->showRet($ret, "drop indexes");

MongoDB查询技巧

第一批

// 特殊查询语句示例
// select * from urls where url = 'http://tfapi.tongfu.net/'
$myDbjObj->search("urls", array('url'=>"http://tfapi.tongfu.net/"));
// select * from urls where url like 'tongfu.net'
$myDbjObj->search("urls", array('url'=>array('$regex'=>"tongfu.net")));
// select * from urls where visit > 100 and visit < 1000
$myDbjObj->search("urls", array('visit'=>array('$gt'=>100, '$lt'=>1000)));
// select * from urls where weight between 3 and 5
$myDbjObj->search("urls", array('weight'=>array('$gte'=>3, '$lte'=>5)));
// select * from urls where urlType <> 'res'
$myDbjObj->search("urls", array('urlType'=>array('$ne'=>"res")));
// select * from urls where urlMediaType in ('avi', 'rmvb', 'rm')
$myDbjObj->search("urls", array('urlMediaType'=>array('$in'=>array("avi","rmvb","rm"))));
// select * from urls where urlMediaType not in ('mov', 'mp4')
$myDbjObj->search("urls", array('urlMediaType'=>array('$nin'=>array("mov","mp4"))));
// select * from urls where catchTool = 'bd' or catchTimes > 0
$myDbjObj->search("urls", array('$or'=>array('catchTool'=>"bd", 'catchTimes'=>array('$gt'=>0))));

$myDbjObj->search("urls", array('urlExtension'=>array('$all'=>array("img","js","css"))));

第二批

// select * from urls where (_id mod 5) = 1
$myDbjObj->search("urls", array('_id'=>array('$mod'=>array(5, 1))));
// select * from urls where not (catchTimes < 100)
$myDbjObj->search("urls", array('$not'=>array('catchTimes'=>array('$lt', 100))));
// 数组中元素同时包含full head
$myDbjObj->search("urls", array('catchType'=>array('$all'=>array('full', 'head'))));
// 数组中第2个元素为head
$myDbjObj->search("urls", array('catchTypes.1'=>"head"));
// 数组元素个数是5个
$myDbjObj->search("urls", array('catchTypes'=>array('$size'=>5)));
// 嵌套查询
$myDbjObj->search("urls", array('catchInfo.status'=>"fail", 'catchInfo.datetime'=>"2018-1-26 15:12:11"));
// 嵌套查询,假定元素是数组的情况下
$myDbjObj->search("urls", array('catchInfo',array('$elemMatch'=>array('status'=>"fail", 'datetime'=>"2018-1-26 15:12:11"))));
// 复杂查询情况(这种方式效率比较慢)
// 尽量依照 正则 > MapReduce > $where 这个顺序设计
$myDbjObj->search("urls", array('$where',"catchTimes > 0 and catchType == 'head'"));
$myDbjObj->search("urls", array('$where',"function(){ var result = catchTimes > 0 and catchType == 'head'; return result; }"));
// 排序,分页实现
// 根据_id反序排列,同时从100行开始取10行数据
$myDbjObj->search("urls", array(), 100, 10, array('_id'=>-1));

第三批

// 将键weightNum的值进行数字增减操作(只能是数字类型)
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$inc'=>array('weightNum'=>1))); $this->showRet($ret, "modRange $inc");
// 向满足条件的文档设置键weightStr值为high(支持嵌套,请使用点符号)
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$set'=>array('weightStr'=>"high"))); $this->showRet($ret, "modRange $set");
// 从满足条件的文档删除键weight.x(支持嵌套,请使用点符号)
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$unset'=>array('weightStr'=>1))); $this->showRet($ret, "modRange $unset");
// 向满足条件的文档的键weightRecord数组追加元素值为s1(不检查重复性)(支持嵌套,请使用点符号)
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$push'=>array('weightRecord'=>"s1"))); $this->showRet($ret, "modRange $push");
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$push'=>array('weightRecord'=>"s1"))); $this->showRet($ret, "modRange $push");
// 向满足条件的文档的键weightRecord数组追加元素值为s1(检查重复性)(支持嵌套,请使用点符号)
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$addToSet'=>array('weightRecord'=>"s1"))); $this->showRet($ret, "modRange $addToSet");
// 向满足条件的文档的键weightRecord数组追加一组元素
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$addToSet'=>array('weightRecord'=>array('$each'=>array("s1","s2","s3"))))); $this->showRet($ret, "modRange $each");
// 使用$pop对键weightRecord数组进行删除元素操作
// 删除数组最后位置元素
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$pop'=>array('weightRecord'=>1))); $this->showRet($ret, "modRange $pop");
// 删除数组最后位置元素
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$pop'=>array('weightRecord'=>-1))); $this->showRet($ret, "modRange $pop");
// 删除数组最后位置元素
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$pop'=>array('weightRecord'=>0))); $this->showRet($ret, "modRange $pop");
// 删除数组匹配条件的元素
$ret = $myDbjObj->modRange("urls", array('_id'=>1), array('$pull'=>array('weightRecord'=>"s2"))); $this->showRet($ret, "modRange $pull");