MongoDB入门

146 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

MongoDB是一个开源文档数据库,提供高性能、高可用性和自动伸缩。

术语和概念

SQLMongoDB
databasedatabase
tablecollection
rowdocument or BSON document
columnfield
indexindex
table joins$lookup, embedded documents
primary key(Specify any unique column or column combination as primary key)primary key(In MongoDB, the primary key is automatically set to the _id field)
aggregation (e.g. group by)aggregation pipeline(See the SQL to Aggregation Mapping Chart)

安装

$ curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz
$ tar -zxvf mongodb-linux-x86_64-3.6.3.tgz
$ cp -R -n mongodb-linux-x86_64-3.6.3/ mongodb
$ vim ~/.bash_profile
	export PATH=<mongodb-install-directory>/bin:$PATH

运行

# mongod进程保存数据目录,默认/data/db,可通过dbpath指定
$ mkdir -p /data/db
# 运行MongoDB --config:指定服务启动配置文件;--auth:开启认证;--dbpath:mongod进程保存数据目录
$ mongod --config /etc/mongod.conf --auth
# 使用MongoDB
$ mongo --host 127.0.0.1 --port 27017 uhe_commission -u uhetrip -p uhetrip
$ mongo 127.0.0.1:27017/uhe_commission -u uhetrip -p uhetrip

/etc/mongod.conf

systemLog:
   destination: file
   path: "/var/log/mongodb/mongod.log"
   logAppend: true
storage:
   dbPath: "/data/db"
   journal:
      enabled: true
processManagement:
   fork: true
   pidFilePath: "/data/software/mongodb-linux-x86_64-3.6.3/mongo.pid"
net:
   bindIp: 0.0.0.0
   port: 27017
setParameter:
   enableLocalhostAuthBypass: false

Linux包初始化脚本包含了MongoDB官方包依赖的特定值systemLog.path, storage.dbPath, and processManagement.fork。如果在默认配置文件中修改这些设置,mongod可能不会启动。

keyvalueDefault说明
systemLog.destinationfile|syslogMongoDB发送所有日志输出的目的地,如指定file,必须同时指定systemLog.path值
systemLog.path"/var/log/mongodb/mongod.log"mongod或mongos应该发送所有诊断日志信息的日志文件的路径
systemLog.logAppendtrue|falseFalse当mongod或mongos重启实例时,true-新的日志添加到现有日志文件的末尾,false-将备份现有日志并创建一个新文件
storage.dbPath"/data/db""/data/db"mongod实例存储数据的目录
storage.journal.enabledtrue|false"/data/db"启用和禁用持久性日志以确保数据文件仍然有效和可恢复。同storage.dbPath一起使用
processManagement.forktrue|falsefalse后台运行mongos或mongod的守护进程模式
processManagement.pidFilePath"/data/mongod.pid"指定一个文件位置来保存mongos或mongod进程的进程ID
processManagement.timeZoneInfo"/usr/share/zoneinfo""/usr/share/zoneinfo"加载时区数据库的完整路径
net.port2701727017MongoDB实例监听的客户端连接TCP端口
net.bindIp0.0.0.0,::localhostTo bind to all IPv4 and IPv6 addresses
net.maxIncomingConnections6553665536mongos或mongod将接受的最大同时连接数
net.wireObjectChecktrue|falsetruemongos或mongod实例会检查客户所有请求,组织无效的BSON插入到MongoDB数据库中
setParameter.enableLocalhostAuthBypass0|falsetrue启用避开本地认证

用户、角色、认证

创建用户

# 超级用户
> db.createUser(
   {
     user: "root",
     pwd: "root",
     roles: [ "root" ]
   }
)
# 管理员用户
> db.createUser(
  {
    user: "admin",
    pwd: "admin",
    roles: [{role: "userAdminAnyDatabase", db: "admin"}]
  }
)

# 数据库管理员用户
> db.createUser(
   {
     user: "uhetrip",
     pwd: "uhetrip",
     roles:
       [{role: "readWrite", db: "uhe_commission"},{role: "dbOwner", db: "uhe_commission"}]
   }
)

内置的角色

role说明
-Database User Roles-数据库用户角色:针对每一个数据库进行控制
read允许用户读取指定数据库所有非系统集合,以及系统集合中的system.indexes, system.js, system.namespaces
readWrite包含了所有read权限,以及修改所有非系统集合的和系统集合中的system.js的权限
-Database Administration Roles-数据库管理角色:每一个数据库包含了下面的数据库管理角色
dbAdmin一些数据库对象的管理操作(如索引创建、删除,查看统计或访问system.profile),但是没有数据库的读写权限
userAdmin为当前用户创建、修改用户和角色。拥有userAdmin权限的用户可以将该数据库的任意权限赋予任意的用户
dbOwner该数据库的所有者,具有该数据库的全部权限
-Cluster Administration Roles-集群管理权限:admin数据库包含了下面的角色,用户管理整个系统,而非单个数据库。这些权限包含了复制集和共享集群的管理函数
clusterAdmin提供了最大的集群管理功能。相当于clusterManager, clusterMonitor, and hostManager和dropDatabase的权限组合
clusterManager提供了集群和复制集管理和监控操作。拥有该权限的用户可以操作config和local数据库(即分片和复制功能)
clusterMonitor仅仅监控集群和复制集
hostManager提供了监控和管理服务器的权限,包括shutdown节点,logrotate, repairDatabase等
-All-Database Roles-所有数据库角色:admin数据库提供了一个mongod实例中所有数据库的权限角色
readAnyDatabase具有read每一个数据库权限。但是不包括应用到集群中的数据库
readWriteAnyDatabase具有readWrite每一个数据库权限。但是不包括应用到集群中的数据库
userAdminAnyDatabase具有userAdmin每一个数据库权限,但是不包括应用到集群中的数据库
dbAdminAnyDatabase提供了dbAdmin每一个数据库权限,但是不包括应用到集群中的数据库
-Superuser Roles-超级管理员权限:
root任何数据库上执行任何操作
-Backup and Restoration Roles-备份恢复角色:
backup
restore

The mongo shell

# 关机
> use admin;
> db.shutdownServer();
# 切换数据库
> use myNewDatabase
# 修改密码
> db.updateUser( "admin",{pwd:"password"});
# 插入数据
> db.myCollection.insertOne( { x: 1 } );
# 格式化输出结果
> db.myCollection.find().pretty();
# 查询条件 $gt(大于); $gte(大于等于); $lt(小于); $lte(小于等于); $ne(不等);
> db.COLLECTION_NAME.find({"age":{$gt:22}})
# 查询条件 $or(或); $in(包含); $nin(排除);
> db.user.find({$or:[{"name":"lihp"},{"name":"tom"}]})
> db.user.find({"address.province":{$in{"hebei","beijing"}}})
# 按ID查询
> db.COLLECTION_NAME.find({ "_id" : ObjectId("55f1b696980f8e29fa26b2b5")})
# 排序 1=升序 -1=降序
> db.COLLECTION_NAME.find().sort({"key":1})
# 时间查询
> db.basestr.find({"expiryTime":{$lte:ISODate("2016-08-16 23:59:59")}}).count()
# 只显示expiryTime字段。1-显示;0-不显示
> db.basestr.find({"expiryTime":{$lte:ISODate("2016-08-16 23:59:59")}},{expiryTime:1}).count()
# 查询指定长度的数组
> db.food.find({“fruit”:{$size:3}})
# 返回数组中的子集. 2:查询前两条数据; -2:查询后两条数据
> db.food.find({“fruit”:{$slice:2}})

索引

#创建测试表
> for (var i=1; i<=100001; i++ ) db.test_4.save({skyid:i,name:'a'});
> db.test_4.find().limit (5);

# 创建唯一索引
> db.test_4.createIndex({key:1},{"name":"idx_basestr_key","unique":true})

# 删除索引
> db.test_4.dropIndex('idx_test_4_skyid');

# 查看表索引
> db.test_4.getIndexes();
[
    {
        "v" : 1,  #索引版本
        "key" : {
            "_id" : 1  #索引项名称,以及索引的排序规则。1:升序;-1:降序
        },
        "name" : "_id_",  #索引名称
        "ns" : "enginedb.test_4"  #索引所在集合名称
    }
]

# 查询分析函数
> db.test_4.find().explain();

Mongo连接池

key说明
connectionsPerHost每个主机最大允许的连接数
threadsAllowedToBlockForConnectionMultiplier线程队列数,它以上面connectionsPerHost值相乘的结果就是线程队列最大值。如果连接线程排满了队列就会抛出“Out of semaphores to get db”错误
maxWaitTime最大等待连接的线程阻塞时间
connectTimeout连接超时的毫秒。0是默认和无限
socketTimeoutsocket超时。0是默认和无限
autoConnectRetry这个控制是否在一个连接时,系统会自动重试
maxConnectionIdleTime最大空闲时间
maxConnectionLifeTime最大存活时间

Mongo 命令

/* MongoDB聚合 aggregate */
db.getCollection('policy').aggregate(
    [
        {$match: {"supplierId" : "681"}},
        {$group: {_id : {"$status","$verifyType"},number : {$sum : 1}}},
        {$sort: {_id : -1 }}
    ]
)

/* MongoDB group分组 */
db.getCollection('policy').group({
    condition:{"supplierId":"681"},
    key: { 'status':1,'verifyType':1},
    initial : {"total":0},
    reduce : function Reduce(doc, out) {
        out.total+=1
    }
});

/* 查询某字段是否存在 */
db.test.find({"check":{$exists:true}});

/* 查询某字段不是null */
db.test.find({"check":{$ne:null}});

/* 查询某字段是null */
db.test.find({"check":null})

/* 指定查询字段 */
db.getCollection('policy').find({"supplierId":"681"},{"policyId":1,"status":1,"verifyType":1})

/* 指定查询字段 */
db.getCollection('policy').find({"supplierId":"681","status":"T"}).forEach(function(item){db.getCollection('policy').update({"_id":item._id},{$set:{"verifyType" : 2}})})

# update(<query>,<update>,<upsert>,<multi>)
/* 会用新的文档代替老的文档 */
/* 第3个参数: insertOrUpdate,即存在即更新,否则插入该数据 */
/* 第4个参数: 批量更新,该参数为true,则批量更新,为false,则更新一条 */
db.getCollection('policy').update({查询器},{修改器},true,false)

/* $set修改器:用来指定一个键值对,如果存在键就进行修改不存在则进行添加 */
{$set:{field: value}}

/* $inc修改器:只是使用与数字类型,他可以为指定的键对应的数字类型的数值进行加减操作 */
{$inc:{field: value}}

/* $unset修改器:用法很简单,就是删除指定的键值对 */
{$unset:{field: 1}}

/* $push修改器:
1.如果指定的键是数组增追加新的数值
2.如果指定的键不是数组则中断当前操作Cannot apply $push/$pushAll modifier to non-array
3.如果不存在指定的键则创建数组类型的键值对
4.此方法可添加重复数据
 */
{$push:{field: value}}

/* $pushAll修改器:批量添加数组数据 */
{$pushAll:{database:["Oracle","MySQL"]}

/* $addToSet修改器:如果目标数组存在此项则不操作,不存在此项则加进去,即不添加重复数据 */
/* $pop修改器:从指定数组删除一个值,1删除最后一个数值,-1删除第一个数值 */
/* $pull修改器:是删除一个被指定的数值 */
/* $pullAll修改器:是一次性删除多个指定的数值 */
/* $数组定位器:如果数组有多个数值我们只想对其中一部分进行操作我们就要用到定位器($) */
{$set:{array.$.field:value}}
Example:
db.sample.update({"database.type":"MongoDB"},{$set:{"database.$.author":"Mongo"}})

参考