MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展
的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰
富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以
存储比较复杂的数据类型。
Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,
几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

MongoDB主要场景如下:
1)网站实时数据处理。非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓存层可以避免下层的数据源过载。
3)高伸缩性的场景。非常适合由数十或数百台服务器组成的数据库,它的路线图中已经包含对MapReduce引擎的内置支持。

不适用的场景如下:
1)要求高度事务性的系统。
2)传统的商业智能应用。
3)复杂的跨文档(表)级联查询。

/*********** Windows版
Windows 安装 msi 包
下载:https://www.mongodb.com/download-center#community
选择 Community Server 选择一个稳定版
安装...

然后找个合适位置 建立目录,用于存放数据和日志:
md "\data\db" "\data\log"

测试启动:(必须指定db路径) */
"C:\Program Files\MongoDB\Server\3.6\bin\mongod.exe" --dbpath="c:\data\db"

/*将 MongoDB 安装为 Windows 服务:
创建配置文件:C:\Program Files\MongoDB\Server\3.6\mongod.cfg
内容如下:(指定了log和db的位置) */
systemLog:
destination: "file"
path: "c:\\data\\log\\mongod.log"
storage:
dbPath: "c:\\data\\db"

// 安装服务:
sc.exe create MongoDB binPath= "\"C:\Program Files\MongoDB\Server\3.6\bin\mongod.exe\" --service --config=\"C:\Program Files\MongoDB\Server\3.6\mongod.cfg\"" DisplayName= "MongoDB" start= auto

// 如果成功则显示:CreateService SUCCESS
// 以后就可以系统服务中管理了。

// 卸载服务:(需要先停止服务)
sc.exe delete MongoDB

/**
管理工具 Robomongo :
下载:https://robomongo.org/download
MongoChef
下载:http://3t.io/mongochef/#mongochef-download-compare
*/
// ----------------------------------------------------------------------------

//-------------------------------------- Linux版 -------------------------------
// Mongodb 需要64位linux 本次使用ubuntu18.0.4 如果是centos,某些命令会不同。
// 到官网下载tar包 tgz,  注意选择OS版本

// https://www.mongodb.com/download-center

tar zxvf mongodb-linux-x86_64-3.6.4.tgz
mv mongodb-linux-x86_64-3.6.4 mongodb364
cd mongodb364

// 建立所需的db文件夹和logs文件夹,在根目录创建,是因为停止服务时,不带参数,会默认寻找此路径
mkdir -p /data/db
mkdir -p /data/logs

// 修改环境变量,vim /etc/profile 添加
export PATH=/home/mongodb364/bin:$PATH

source /etc/profile // 生效

// ------------如果不能启动服务,ubuntu18 可能需要安装某些依赖。--------------
// 如果 apt-get 出现 E: Unable to locate package 问题, 则执行以下命令:
add-apt-repository main
add-apt-repository universe
add-apt-repository restricted
add-apt-repository multiverse

apt-get update
// 如果不能解决,再执行这条:
apt-get upgradee

// 移除某个包:
apt-get remove xxx

// 错误: libcurl.so.4: version `CURL_OPENSSL_3' not found
apt-get install curl
apt-get install libcurl3

// CentOS的依赖
yum install libcurl openssl  // 安装依赖

// 启动服务    指定路径       --port 10086 指定端口
bin/mongod --dbpath=/opt/mongodb/data/db --logpath=/opt/mongodb/logs/mongo.log --fork bin/mongo --help // 使用客户端帮助
bin/mongo // 首次本机登录无需认证 bin/mongod --config /etc/mongod.conf // 或者指定配置文件启动,通常在设置安全后 // 停止服务 mongod --shutdown // 不指定dbpath, 默认会寻找 /data/db
// 停止服务 mongod --shutdown --dbpath /home/mongodb364/data/db // 指定dbpath
// 停止服务 mongod --shutdown --config=/etc/mongod.conf // 也可指定配置文件
/************* 安全性流程:
1.创建超级管理员
2.修改配置文件,启用身份验证
3.重启服务
4.使用超级管理员登录
5.创建并使用普通用户
*************/
// -------------------------------使用配置文件:--------------------------
vim /etc/mongod.conf // 较简单的格式
bind_ip = 0.0.0.0
port=27017
dbpath=/data/db
logpath=/data/logs/mongod.log
pidfilepath=/opt/mongodb/mongod.pid
fork=true
logappend=true
auth=true

// ---------------------------YAML格式配置文件--------------------------

如果是 rpm / yum 方式安装,则自动添加 /etc/mongo.conf ,示例:

# mongod.conf

# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/ # where to write logging data.
systemLog:
destination: file
logAppend: true
path: /data/logs/mongod.log # Where and how to store data.
storage:
dbPath: /data/db
directoryPerDB: true
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger: # how the process runs
processManagement:
fork: true # fork and run in background
pidFilePath: /opt/mongodb/mongod.pid # location of pidfile
timeZoneInfo: /usr/share/zoneinfo # network interfaces
net:
port: 27017
bindIp: 127.0.0.1 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting. security:
authorization: "enabled"
#operationProfiling: #replication: #sharding: ## Enterprise-Only Options #auditLog: #snmp:

bin/mongod --config /etc/mongod.conf // 指定配置文件启动
// 如果启动失败,请检查配置中文件路径是否正确

//------------------------配置远程连接---------------------------------
systemctl status ufw // 查看防火墙状态
systemctl stop ufw // 停止防火墙
ufw allow // 防火墙允许端口
// --------上面是ubuntu的,下面是centos7的。--------------------------
firewall-cmd --permanent --add-port=/tcp // 添加3306
systemctl restart firewalld.service // 重启fw
firewall-cmd --list-all // 查看fw

如果需要,也可将Mongodb安装为服务,便于管理

############# 在 CentOS7 中安装为服务
# 1. 创建用户和组
groupadd -g mongogrp
useradd -u -g mongogrp -G mongogrp mongouser
passwd mongouser # 2. 更改mongodb文件夹拥有者
chown -R mongouser:mongogrp mongod/ # 3.编辑服务文件 /etc/systemd/system/mongod.service 并保存
# 写User和Group是限制指定用户可以操作
[Unit]
Description=MongoDB Server
After=network.target remote-fs.target nss-lookup.target [Service]
User=mongouser
Group=mongogrp
Type=forking
ExecStart=/data/mongod/bins/mongod -f /data/mongod/conf/mongod.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/data/mongod/bins/mongod --shutdown -f /data/mongod/conf/mongod.conf
PrivateTmp=true
LimitFSIZE=infinity
LimitCPU=infinity
LimitAS=infinity
LimitNOFILE=64000
LimitNPROC=64000 [Install]
WantedBy=multi-user.target

# 4. 试试用 mongouser 操作服务
sudo systemctl daemon-reload
sudo systemctl start mongod
sudo systemctl status mongod
sudo systemctl stop mongod
sudo systemctl enable mongod # 开机启动
sudo systemctl disable mongod # 关闭开机启动
sudo systemctl is-enabled mongod # 检查是否开机启动
sudo systemctl kill mongod # 杀死进程mongod sudo systemctl list-units -t service # 列出已激活的服务
sudo systemctl list-units -t service -a # 列出所有服务

//###########################  mongo shell  ####################################

mongo  // 登录本机(未开启认证时)
// 执行以下命令,可以添加 管理员
use admin;
db.createUser(
{
user: "admin",
pwd: "admin",
roles: [ { role: "root", db: "admin" } ]
}
); /** 下面是成功时返回的提示:
Successfully added user: {
"user" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
};
**/
db.auth("admin","admin") // 认证测试,若 1 则成功 //----------------------------------------------------------------------------- // 如开启认证:
use admin // 进入管理库
db.auth("username","pwd") // 认证登录 // 或直接认证连接: 本地方式
mongo --username admin --password --authenticationDatabase admin
mongo -u admin -p --authenticationDatabase admin
// 远程方式
mongo "mongodb://admin:pwd@localhost:27017/?authSource=admin"

// 更多连接实例
// 参考: https://www.mongodb.org.cn/tutorial/7.html //连接本地数据库服务器,端口是默认的。
mongodb://localhost
//使用用户名fred,密码foobar登录localhost的admin数据库。
mongodb://fred:foobar@localhost
//使用用户名fred,密码foobar登录localhost的baz数据库。
mongodb://fred:foobar@localhost/baz //连接 replica pair, 服务器1为example1.com服务器2为example2。
mongodb://example1.com:27017,example2.com:27017
//连接 replica set 三台服务器 (端口 27017, 27018, 和27019):
mongodb://localhost,localhost:27018,localhost:27019
//连接 replica set 三台服务器, 写入操作应用在主服务器 并且分布查询到从服务器。
mongodb://host1,host2,host3/?slaveOk=true
//直接连接第一个服务器,无论是replica set一部分或者主服务器或者从服务器。
mongodb://host1,host2,host3/?connect=direct;slaveOk=true
//当你的连接服务器有优先级,还需要列出所有服务器,你可以使用上述连接方式。 //安全模式连接到localhost:
mongodb://localhost/?safe=true
//以安全模式连接到replica set,并且等待至少两个复制服务器成功写入,超时时间设置为2秒。
mongodb://host1,host2,host3/?safe=true;w=2;wtimeoutMS=2000


// Shell 常用操作
db
show dbs
show collections
use local
show users // 查看当前库中用户
db.test.insert({'a':''}) // 插入数据时会自动创建库和Collections
db.test.find() // 显示所有数据 exit // 退出mongo shell // 最后用Robo 3T 测试连接
/*************** 如果需要重置密码: ***************/
// 1. 停止服务 mongod --shutdown --config=/etc/mongod.conf
// 2. 修改conf文件,关掉security和authorization
// 3. 启动服务 mongod --config /etc/mongod.conf
// 4. mongo 登录,use admin ,
show users // 显示本库用户
db.system.users.find() // 查看全部用户信息。
db.dropUser(用户名) // 删除指定的用户
// 5. 使用上面的 db.createUser 添加用户:
use admin
db.createUser(
{
user: "admin",
pwd: "admin",
roles: [ { role: "root", db: "admin" } ]
}
); // 或者修改用户:
db.updateUser('admin',
{
pwd: "admin",
roles: [{ role: "root", db: "admin" } ]
}
)
// 6. 重新开启配置文件的安全选项,并重启服务

/*********** Mongodb内置的用户角色:
1. 数据库用户角色:read、readWrite
2. 数据库管理角色:dbAdmin、dbOwner、userAdmin
3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
4. 备份恢复角色:backup、restore
5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
6. 超级用户角色: root (最大权限,可访问所有库)
间接或直接提供了系统超级用户访问的角色:dbOwner、userAdmin、userAdminAnyDatabase
7. 内部角色:__system

#  创建一个 __system 用户,可以访问 所有元数据

db.createUser({user:"sa", pwd:"123456", roles:[{role:"__system", db:"admin"}]})  

获得数据库的所有用户权限信息:db.getUsers()

获得某个用户的权限信息:db.getUser()
创建角色: db.createRole()
更新角色:db.updateRole()
删除角色:db.dropRole()
获得某个角色信息:db.getRole()
删除用户:db.dropUser()
删除所有用户:db.dropAllUsers()
将一个角色赋予给用户:db.grantRolesToUser()
撤销某个用户的某个角色权限:db.revokeRolesFromUser()
更改密码:db.changeUserPassword()

***********/

    // 例1:给test库添加用户,只能访问test   即 --authenticationDatabase test
use test
db.createUser(
{
user: "test1",
pwd: "test1",
roles: [ { role: "readWrite", db: "test" } ]
}
); // 例2:修改user1权限 --authenticationDatabase demo
use demo
db.updateUser('user1',{
roles: [{role:"dbOwner", db:"demo"}]
}) // 例3:修改test用户权限,读写所有库
use admin
db.updateUser('test',{
roles: [{role:"readWriteAnyDatabase", db:"admin"}]
}) /************ 其它命令 ******
创建 capped collection 上限集合:
size:大小KB,如果size字段小于或等于4096,则集合的上限为4096字节
max: 最大文档数。size参数总是必需的,即使指定max的文件数量。
如果集合在达到最大文档计数之前达到最大大小限制,MongoDB将删除旧文档。
参考官方文档 或 https://www.jianshu.com/p/86942c09094a
************/
db.createCollection("sub",{capped:true,size:,max:}) db.sub.isCapped() // 检查是否 capped // 转换为 capped 集合
db.runCommand({"convertToCapped": "test", size: , max: });

/**************
*** CURD ***
**************/

//----------------------------------- 增 ---------------------------------------
// Mongodb 数据库名称不区分大小写
// 数据库不必创建,直接 use databasename 即可
// 集合名称可以createCollection创建,
// 一般集合也可不创建,直接在插入数据时自动生成。
// 集合名称只能字母或下划线开头,不能包含 . $ 和空字符,不能 system. 开头
// 更多限制,参考官文:https://docs.mongodb.com/manual/reference/limits/
// 插入多条
db.users.insert([
{name:'Allan',age:,gender:},
{name:'Bob',age:,gender:},
{name:'Celine',age:,gender:},
{name:'Dennis',age:,gender:},
]) // 以下两种插入方法是为了语义清晰
// db.test.insertOne()
// db.test.insertMany() // ================================== 查 =======================================
db.test.find({}) // 空对象或空,查询所有的
db.test.find({name:"Jerry"}) // 返回数组
db.test.findOne({name:"Jerry"}) // 返回对象
db.test.find({}).count() // 数量 或 db.test.count()
db.users.count({age:{$gt:}}) // 条件数量
db.test.find({age:{$gt:}}) // 大于 或者 $gte 即 >=
db.test.find({create_ts:{$gt:ISODate("2019-09-19T00:00:00.000Z")}}).pretty() //大于某时间
db.test.find({age:{$eq:}}) // 等于 或者 $ne 不等于
db.test.find({age:{$lt:}}) // 小于 或者 $lte 即 <=
db.test.find({age:{$gt:, $lt:}}) // 大于且小于
db.demoes.find({$or:[{num:{$lt:}},{num:{$gt:}}]}) // 或 $or:[{},{},]
db.users.find({age:{$in:[,]}}) // 在in 或 不在nin
db.users.find({name:/^C/}) // 正则,以C开头
db.users.find({name:{$regex:"^A"}}) // 正则, 以A开头
db.users.find({nickname:{$exists: false}})  // 找出不存在昵称字段的 (true 存在)
// 虽然可用JS语法,但是效率低
db.users.find({$where:function(){return this.age>}})
db.users.find({$where:function(){return this.name.startsWith("C")}}) db.test.find().limit() // 前10条
db.test.find().skip().limit() // 跳过10条
// 官方文档也提到 skip() 由于是从头开始数,所以,当数据量变大时,会变得非常慢。
// 我测试的时候,大于5万条数据,已经很慢了。 所以,尽量使用 条件查询,避免使用 skip() // skip( (页码 -1) * 每页条数).limit(每页条数)
// limit()与skip()或sort() 前后无关,mongodb自动调整 db.test.find().sort({age:-}) // 按年龄降序 // 1取0不要,只有_id需要特别指定为0
db.test.find({},{name:, _id:, age:}) // 投影:只要name和age,不要_id
db.users.distinct("gender", {age:{$lt:}}) // 年龄小于20的性别 // --------------------------------- 改 ----------------------------------------
// db.test.update({_id:ObjectId("5cede5d81f3b03073319abd0")},{age:23}) // 小心,新对象替换旧对象
// 应该使用修改符来操作
db.test.update({_id:ObjectId("5cede5d81f3b03073319abd0")},{$set:{name:"老沙", gender:"男",address:"流沙河"}})
db.test.update({_id:ObjectId("5cede5d81f3b03073319abd0")},{$set:{age:}})
db.test.update({_id:ObjectId("5cede5d81f3b03073319abd0")},{$unset:{address:}}) // 删除某字段 只删除第一个匹配到的
// $unset 删除字段时,字段写什么值并不影响结果。

db.test.update({},{$unset:{"Profiles":""}},{multi:true})      // 删除了所有的 Profiles 字段
  // db.test.update({},{$unset:{"Profiles":""}})
  db.test.update({},{$unset:{"Qr":"SOCKET_EMPTY"}},{multi:true})  // 删除所有的 Qr 字段

db.test.update({name:"AAAA"},{$set:{address:"test"}})       // 默认只改一条
db.test.update({name:"AAAA"},{$set:{address:""}},{multi:true}) // 使用multi改所有的 db.test.updateMany({name:"AAAA"},{$set:{address:""}}) // 改所有符合的
db.posts.updateMany({created_at:{$exists:false}},{$set:{created_at:'2019-07-08 16:20:00'}}) // 不存在某字段时,加上 /* ********************************* 删 ****************************************/
db.test.remove({address:""}) // 默认删除全部匹配的行
db.test.remove({address:""}, true) // 只删除一行
db.test.remove({},true) // 删除第一行
db.test.remove({}) // 清空集合 db.test.drop() // 删除集合
db.dropDatabase() // 删当前库(赶紧跑路) // 通常上面的都不会执行, 使用字段isDel代替
db.test.updateOne({name:"AAAA"},{$set:{isDel:}})
db.test.find({isDel:})
// $type 操作符 https://www.mongodb.org.cn/tutorial/15.html
db.test.find({"title" : {$type : 2}}) // 条件:字段为string类型

// -----------#-----------#----------- 练习 ------#-----------#-----------#-------

// 属性值也可以是个文档 即 内嵌文档
db.goods.update({name:"CPU"},{$set:{band:{Intel:["I3","I5","I7"],AMD:["R5","R7"]}}})
db.goods.find({'band.AMD':'R5'}) // 查询内嵌时必须引号, 包含
db.goods.find({'band.AMD':'R5'},{'band.AMD.$':1}) // 仅取出AMD.R5的列表元素,不要其它的元素。 db.goods.update({name:"Mem"},{$push:{'band.KST':''}}) // 插入一个,可重复
db.goods.update({name:"Mem"},{$addToSet:{'band.KST':''}}) // 添加到集合,不重复
db.goods.update({name:"Mem"},{$pop:{'band.KST':}}) // 移除最后一个元素 //# 插入20000条数据
// 1. 笨方法:
for(var i=; i<;i++){
db.demos.insert({num:i})
} // 2. 好方法:
var arr=[];
for(var i=; i<;i++){
arr.push({num:i});
}
db.demoes.insert(arr)

文档间关系

//# 1. 一对一:通过内嵌文档的形式.
db.married.insert([
{name:"Tom",guy:{name:"Jerry"}},
{name:"大郎",guy:{name:"金莲"}}
]) //# 2. 一对多, 多对一:
db.users.insert([
{username:"swk"},
{username:"zbj"}
]) db.order.insert([
{list:["CPU","Mem","Disk"],
user_id: ObjectId("5cef98a9e4a985f4ad3e897c")
},
{list:["Apple","Pear","Cherry"],
user_id: ObjectId("5cef98a9e4a985f4ad3e897c")
}
]) db.order.insert(
{list:["Pig","Donkey","Sheep"],
user_id: ObjectId("5cef98a9e4a985f4ad3e897d")
}) // 查询
var user_id=db.users.findOne({username:"swk"})._id;
db.order.find({user_id:user_id}) //# 3. 多对多:
db.teacher.insert([
{name:"如来"},
{name:"观音"},
{name:"菩提"}
]) db.students.insert([
{"name" : "Tom",
"teacher_ids" : [
ObjectId("5cefbdffe4a985f4ad3e8984"),
ObjectId("5cefbdffe4a985f4ad3e8982")
]},
{"name" : "Jerry",
"teacher_ids" : [
ObjectId("5cefbdffe4a985f4ad3e8984"),
ObjectId("5cefbdffe4a985f4ad3e8983")
]}
]) // 查询: 如来的徒弟
var tid = db.teacher.find({name:"如来"})[]._id // 或
var tid = db.teacher.findOne({name:"如来"})._id
db.students.find({teacher_ids:tid}) //-----------------#----------------- 练习 ------------------#-------------------
// 1. 找出财务部员工
var deptno = db.dept.findOne({dname:"财务部"}).deptno
db.emp.find({deptno:deptno}) // 2. 低于1000的加400
db.emp.updateMany({sal:{$lt:}},{$inc:{sal:}})
db.emp.updateMany({deptno:},{$inc:{sal:}}) // IT部加工资 // 3. 价高于300的减100
db.goods.updateMany({price:{$gt:}},{$inc:{price:-}})

管道

// aggregate 用于聚合统计,$group 类似于SQL的sum(), avg() 

// 各求男女人数
db.users.aggregate([{$group:{_id:'$gender',counter:{$sum:}}}]) db.users.aggregate([{$group:{_id:'$gender',counter:{$sum:'$age'}}}]) // 年龄合计
db.users.aggregate([{$group:{_id:'$gender',counter:{$avg:'$age'}}}]) // 平均年龄
db.users.aggregate([{$group:{_id:'$gender',counter:{$max:'$age'}}}]) // 或 min
db.users.aggregate([{$group:{_id:'$gender',counter:{$first:'$age'}}}]) // 或 last // 列出各年龄到数组,不去重
db.users.aggregate([{$group:{_id:'$gender',counter:{$push:'$age'}}}]) // 男女分组,列出name到数组
db.users.aggregate([{$group:{_id:'$gender',counter:{$push:'$name'}}}]) // 男女分组,基于整个文档列出所有字段到数组
db.users.aggregate([{$group:{_id:'$gender',counter:{$push:'$$ROOT'}}}]) //## $match
db.users.aggregate([{$match:{age:{$gt:}}}]) // 筛选 // 将筛选后的结果再聚合
db.users.aggregate([
{$match:{age:{$gt:}}},
{$group:{_id:'$gender',counter:{$sum:}}}
]) // 筛选,聚合,投影
db.users.aggregate([
{$match:{age:{$gt:}}},
{$group:{_id:'$gender',counter:{$push:'$name'}}},
{$project:{_id:,counter:}}
]) // 排序,和find()中的几乎一样 {$sort:{_id: -1}} 也可以用在多个地方
db.users.aggregate([
{$match:{age:{$gt:}}},
{$sort:{name: }},
{$group:{_id:'$gender',counter:{$push:'$name'}}},
{$sort:{_id:-}}
]) // 内按name升序,外按_id降序 // 跳过 {$skip:10},限制{$limit:5} 此处区分顺序 /**
* {$unwind:"$counter"} 将数组字段拆开成单条
*/
db.students.aggregate([
{$match:{name:"WuKong"}},
{$unwind:"$teacher_ids"}
]) db.t3.insert([
{"_id":,"item":"a","size":["S","M","L"]},
{"_id":,"item":"b","size":[]},
{"_id":,"item":"c","size":"M"},
{"_id":,"item":"d"},
{"_id":,"item":"e","size":null},
]) db.t3.aggregate([{$unwind:{path:"$size"}}]) // 取出值 不含空和null以及无字段 // 取出值,不丢任何数据
db.t3.aggregate([
{$unwind:{path:"$size", preserveNullAndEmptyArrays:true}}
]) // 示例1:找出几个字段组合的重复数据
db.products.aggregate([
{
'$group': {
'_id': {
'Product': '$Product',
'Machine': '$Machine',
'Station': '$Station',
'Status': '$Status',
'Price': '$Price'
},
'uniqueIds': {
'$addToSet': '$_id'
},
'count': {
'$sum': 1
}
}
},
{
'$match': {
'count': {
'$gt': 1
}
}
}],
{
allowDiskUse: true
});

// 示例2: 排除某个状态的重复数据查找

db.members.aggregate([
{'$match': {'Status': {'$ne': '-1'}}},
{
'$group': {
'_id': {
'Station': '$Station',
'Name': '$Name'
},
'uniqueIds': {
'$addToSet': '$_id'
},
'count': {
'$sum': 1
}
}
},
{
'$match': {
'count': {
'$gt': 1
}
}
}
], {
allowDiskUse: true
});
 

索引

/********************************** 索引 **************************************/
db.t1.ensureIndex({name:}) // 添加索引
db.t1.ensureIndex({name:}, {unique:true}) // 多参数
db.t1.ensureIndex({name:,age:}) // 联合索引
db.t1.getIndexes() // 查询索引
db.t1.dropIndex("name_1") // 删除指定索引
db.t1.dropIndexes() // 删除全部索引,保留默认 _id_ 索引 // 测试数据
let arr=[];
for(let i=;i<;i++){
arr.push({name:"test"+i, age:i});
}
db.t1.insert(arr) // 性能评估 其中结果 executionTimeMillis 为毫秒
db.t1.find({name:'test9999'}).explain('executionStats') db.t1.ensureIndex({name:}) // 添加索引 // 再次执行 结果 executionTimeMillis 降低很多
db.t1.find({name:'test9999'}).explain('executionStats') // 删除数据时,索引不会删除,并且体积可能变得更大,必要时可以删除索引,重建索引。

/*************************** 复制集 ******************************/

// 官文 https://docs.mongodb.com/manual/replication/

主备

// 例1:单机演示。(生产环境不适用)使用不同端口,不同数据目录,必须设置相同 replSet
mongod --bind_ip 192.168.112.9 --port --dbpath /data/t1 --replSet rs0
mongod --bind_ip 192.168.112.9 --port --dbpath /data/t2 --replSet rs0
// 服务运行窗口可以看到后续操作的日志显示 // 然后客户端分别连接服务
mongo --host 192.168.112.9 --port
rs.initiate() // 初始化为master 提示符发生变化
rs.status() // 查看复制集状态 rs0:PRIMARY>
rs.isMaster() // 是否主节点
rs.add("192.168.112.9:27019") // 添加slave mongo --host 192.168.112.9 --port
rs.slaveOk() // slave上执行同意 // 例2:不同机器(接近生产环境)。必须设置相同 replSet
// 注意OS版本,rs1:PRIMARY 可低版本,rs1:SECONDARY可高版本。反之则rs.add出错
// 本例PRIMARY为112.6(centos6.5), SECONDARY为112.9(centos7.5)
mongod --bind_ip 192.168.112.6 --port --dbpath /data/t3 --replSet rs1
mongod --bind_ip 192.168.112.9 --port --dbpath /data/t3 --replSet rs1 // 使用客户端分别连接服务
mongo --host 192.168.112.6 --port
mongo --host 192.168.112.9 --port rs.initiate() // 112.6 为 master
rs.status() // 查看复制集状态 rs1:PRIMARY>
rs.add("192.168.112.9:27018") // 添加slave rs.slaveOk() // 112.9 上执行同意 // 测试数据 master
use demo1
db.users.insert({name:"Allen",age:})
db.users.insert({name:"Bob",age:}) // slave上查询
use demo1
db.users.find() // 得到相同结果 // 发现master当机后,某slave则自动变为PRIMARY
// 而修好后的master启用,加入到rs1,转为SECONDARY

/////////////////////// 添加一个节点(192.168.112.7:27017)
// 新节点 安装,添加目录,然后执行:
mongod --bind_ip 192.168.112.7 --port 27017 --dbpath /data/t3 --replSet rs1
// 然后 rs1:PRIMARY> 上执行:
rs.add("192.168.112.7:27017") // 添加slave节点
// slave 新窗口上执行:
mongo --host 192.168.112.7 --port 27017
> rs.slaveOk() // 即可自动更新所有数据 /////////////////////// 删除一个节点
rs1:PRIMARY> rs.remove("192.168.112.6:27018") // 被删节点将不可用 /////////////////////// 停止节点服务
mongod --bind_ip 192.168.112.7 --port 27017 --dbpath /data/t3 --shutdown // 其它命令:
rs.conf() // 显示复制集信息
rs.printReplicationInfo() // 从primary角度显示复制集信息,显示 oplog 信息
rs.printSlaveReplicationInfo() // 从secondary角度显示复制集信息
db.serverStatus().asserts // 查看断言
rs.stepDown() // 强制primary降为secondary,并引发新的选举. 慎用

#故障案例:某个 slave 节点自动down掉,再次启动时过一会还是down掉,检查日志后发现:
[replication-0] We are too stale to use 10.1.1.34:27017 as a sync source. Blacklisting this sync source because our last fetched timestamp: 
Timestamp(1584041941, 30) is before their earliest timestamp: Timestamp(1584399943, 455) for 1min until:

解决办法:将此 slave 停止服务, 改名或删除 mongodb 仅数据目录后,重新启动 mongodb, 如果状态显示为 startup2 则表示成功开始同步数据。等待同步完成即可恢复正常。

备份与恢复

// mongodump -h dbhost -d dbname -o outdir
// 备份将在输出目录中生成Collection对应的 bson 和 metadata.json 文件
mongodump -u admin -p admin --authenticationDatabase admin -h 192.168.112.9 -d test -o /bak/mongodb // 恢复 mongorestore -h dbhost -d dbname --dir inputdir
mongorestore -u admin -p admin --authenticationDatabase admin -h localhost -d test --dir /bak/mongodb/test/

Python pymongo

// driver for python
pip3 install pymongo

/*************************************** demo.py ******************************/

#!/usr/bin/env python
# coding:utf-8 from pymongo import * client = MongoClient('mongodb://test1:test1@192.168.112.9:27017/test') db = client.test # 库
users = db.users # Collections # res = users.insert({'name':'python','age':88,'gender':'female'}) # 插入
# print(res) # 返回 id
# ret = users.insert_one({'name':'pip3','age':19,'gender':'male'}) # 插入
# print(ret) # 返回 object # ret2 = users.update_one({'name':'python'},{'$set':{'name':'Python3'}}) # 修改
# print(ret2) # ret3 = users.delete_one({'name':'pip3'}) # 删除
# print(ret3) # cursor = users.find_one({'name':'Python3'}) # 只取一条
# print(type(cursor), cursor)
# for k, v in cursor.items():
# print(k + " --> " + str(v)) # cursor = users.find({'age':{'$gt':30}}) # 取多条
# for s in cursor:
# print(s)
# # print(s['name'], s['age']) # cursor = users.find().sort([('gender',1),('age',-1)]) # 多条件降序
# for s in cursor:
# print(s) cursor = users.find().sort('age',-1).limit(2).skip(3) # 子集
for s in cursor:
print(s)

Node.js  mongoose

因为npm 库中的 mongodb没有这个好用,所以直接使用 mongoose

/**
1. 安装
npm i mongoose --save 2. 引入
let mongoose = require("mongoose"); 3. 连接数据库
mongoose.connect('mongodb://root:123456@192.168.112.9/odm_demo?authSource=admin',{useNewUrlParser:true});
默认27017可以省略
通常只需连接一次,除非项目停止或服务器关闭,否则连接一般不会断开。 4. 断开连接(一般不需要)
mongoose.disconnect();
一般情况下,只需要连接一次; 除非项目停止服务器关闭,否则连接一般不会断开 - 监听Mongodb连接状态
- 在mongoose对象中,有一个属性叫做connection 表示的就是数据库连接
通过监视该对象的状态,可以来监听数据库的连接与断开 - 连接成功事件
mongoose.connection.once("open",function(){}); - 数据库断开事件
mongoose.connection.once("close",function(){});
*/ const mongoose = require('mongoose'); mongoose.connect('mongodb://admin:admin@192.168.112.9/admin', {useNewUrlParser: true}); // 正确写法 mongoose.connection.once('open',function () {
console.log("连接成功.");
}); mongoose.connection.once('close',function () {
console.log('数据库已断开.');
}); mongoose.disconnect(); // 一般不会调用

mongoose demo

const mongoose = require('mongoose');

mongoose.connect('mongodb://root:123456@192.168.112.9/odm_demo?authSource=odm_demo',{useNewUrlParser:true});
mongoose.connection.once('open',function (err) {
if(err){
console.log(err);
}else{
console.log("连接成功~~~");
}
}); /**
* Schema
* Model
* Document
*/ // 1. 定义 Schema
let Schema = mongoose.Schema; // 2. 创建模式(约束) Schema 对象
let stuSchema = new Schema({
name: String,
age: Number,
gender:{
type: String,
default:"female"
},
address:String
}); // 3. 通过Schema创建 Model (Collection),通过Model才能操作数据库
let StuModel = mongoose.model("child", stuSchema); // 集合名自动变复数 // 4. 插入文档 Model.create(doc,function (err) {});
StuModel.create({
name:"紫霞仙子",
age:18,
// gender:"male",
address:"水帘洞"
},function (err) {
if(!err){
console.log("插入成功.");
}
});

模型用法示例

require("./common/conn_mongo");
let StuModel = require('./model/users'); // 插入 Model.create(doc(s),[callback])
/* StuModel.create([
{
name:"沙和尚",
age:42,
gender:"male",
address:"流沙河"
}
],function (err) {
if(!err){
// console.log('插入成功~~~');
console.log(arguments); // 返回插入的内容
}
}); StuModel.create(
[{
name:'白骨精',
age:90,
address:'山洞'
},{
name:'女王',
age:38,
address:'女儿国'
}], function (err) {
if(!err){
console.log('插入成功.')
}
}
); */ /** 查询:
* Model.find(conditions,[projection],[options],[callback])
* 查询所有符合条件的文档 返回数组
* Model.findById(id,[projection],[options],[callback])
* 根据ID属性查询文档
* Model.findOne([conditions],[projection],[options],[callback])
* 查询符合条件的第一个文档
*
* Model.count(conditions, [callback]) // 数量
*
* - projection 投影 想要的字段
* 两种方式: {name:1, _id:0}
* "name -_id"
* - options 选项(skip, limit )
* {skip:2, limit:1}
* - callback 回调函数 必传, 不传则不会查询
*/ // StuModel.count({},function (err, count) { // count 是旧方法
StuModel.countDocuments({},function (err, count) { // 新方法
if(!err){
console.log(count);
}
}); StuModel.find({name:"八戒"},function (err,docs) { // 返回数组
if(!err){
if(docs.length > 0){
console.log(docs)
// console.log(docs[0].name)
}else{
console.log('docs is empty')
}
}
}); StuModel.findOne({name:"唐僧"},function (err, doc) { // 返回文档对象, 就是Document
if(!err){
if(doc){
// console.log(doc)
console.log(doc.address);
console.log(doc instanceof StuModel) // Document对象是Model的实例
}else{
console.log('no result')
}
}
}); StuModel.findById('5d108a9fe15d35242c37666c',function (err, doc) {
if(!err){
console.log(doc.name);
}
}); // // 投影 只取name age 不要 _id
// StuModel.find({},{name:1, age:1, _id:0},function (err, docs) { // 对象参数
StuModel.find({},'name age -_id', {skip:1,limit:1}, function (err, docs) { // 字符串参数
if(!err){
if(docs.length > 0){
console.log(docs)
}
}
}); /** 修改
* Model.update(conditions, doc, [options], [callback])
* Model.updateMany(conditions, doc, [options], [callback])
* Model.updateOne(conditions, doc, [options], [callback])
* Model.replaceOne(conditions, doc, [options], [callback])
* - conditions 查询条件
* - doc 修改后的对象
*/ StuModel.updateOne({name:"唐僧"},{$set:{age:77}},function (err) {
if(!err){
console.log('修改成功.');
}
}); /** 删除 一般不用
* Model.remove(conditions, [callback])
* Model.deleteOne(conditions, [callback])
* Model.deleteMany(conditions, [callback])
*/ // StuModel.deleteOne({name:'白骨精'},function (err) {
// if(!err){
// console.log('删除成功.')
// }
// });

common/conn_mongo.js

let mongoose = require("mongoose");

mongoose.connect('mongodb://admin:admin@192.168.112.9/odm_demo?authSource=admin',{useNewUrlParser:true});
mongoose.connection.once('open',function (err) {
if(err){
console.log(err);
}else{
console.log("连接成功~~~");
}
});

model/users.js

/**
定义模型
*/ const mongoose = require('mongoose');
let Schema = mongoose.Schema; let stuSchema = new Schema({
name: String,
age: Number,
gender:{
type: String,
default:"female"
},
address:String
}); // 有了model 即可CURD
let UsrModel = mongoose.model("users", stuSchema); // 如果是复数,则名称不变
module.exports = UsrModel;

文档用法示例:

require('./common/conn_mongo');
let monster = require('./model/monster'); /**
* Document 和 集合中的文档一一对应,Document是Model的实例
* 通过 Model 查询到的结果都是 Document
*/
let stu = new monster({
name:"奔波儿霸",
age:888,
gender:"male",
address:"碧波潭"
}); // console.log(stu); // Document对象的方法 Model#save([options],[fn])
// 而 create 是 Model 的方法
// stu.save(function (err) {
// if(!err){
// console.log("写入成功~")
// }
// }); monster.findOne({},function (err, doc) {
if(!err){
/**
* update(update,[options],[callback]))
* - 修改对象
* save([callback]))
* update([callback]))
*/
// console.log(doc);
// doc.update({$set:{age:22}},function (err) { // 过时的方法
// if(!err){
// console.log("修改成功.")
// }
// }); // doc.updateOne({$set:{address:"高老庄"}},function (err) {
// if(!err){
// console.log("修改成功");
// }
// }); // // 直接修改
// doc.age = 2000;
// doc.save(); // 删除
// doc.remove(function (err) {
// if(!err){
// console.log("师傅再见~")
// }
// }) /**
* get(name)
* set(name, value)
* id 获取文档的 _id 属性
* toJSON()
* toObject() document对象方法则失效
*/
console.log(doc.get("name"));
console.log(doc.address); // doc.set("name","猪悟能"); // 需要 save() 才能修改数据库
// doc.name = "奔波霸";
// doc.save();
console.log(doc.id); console.log(typeof doc); // Object
let t = doc.toObject(); // 转为普通 JS 对象
delete t.__v;
delete t._id;
console.log(t);
}
});

model/monster.js

const mongoose = require('mongoose');
let Schema = mongoose.Schema;
let stuSchema = new Schema({
name: String,
age: Number,
gender:{
type: String,
default:"female"
},
address:String
}); let MonsterModel = mongoose.model("monsters", stuSchema);
module.exports = MonsterModel;

Mongodb基础 学习小结的更多相关文章

  1. MongoDB基础学习

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  2. mongodb基础学习2-基本CRUD

    接着学习一下mongodb的基本的CRUD 先列出基本知识点,再给出相关的例子 增:语法: db.collectionName.insert(document); 1: 增加单篇文档,不指定_id时会 ...

  3. mongodb基础学习8-复制集

    今天来简单学习一下复制集(replication),什么是复制集呢,类似于mysql的主从复制吧 简单来说就是有多个mongodb的实例,多个实例有相同的内容,其中一台用于读写,其它用于备份,当用于读 ...

  4. mongodb基础学习1-基本说明及安装

    以前看过一些mongodb的视频,但只看到一半没有看完,也没有同步安装软件动手操作,正好最近没事,打算花点时间从头学习一遍,边学习边动手操作,学习的过程在此进行记录. 好了,下面说一下今天的学习内容. ...

  5. MongoDB基础学习(一) MongoDB概念解析

    .基础概念 SQL术语/概念 MongoDB术语/概念 说明 database database 数据库 table collection 数据表/集合 row document 数据记录行/文档 c ...

  6. Mongodb分片 学习小结

    前一篇 https://www.cnblogs.com/frx9527/p/mongodb.html 学会搭建复制集Replication之后,就可以学习分片Sharding了. 教程建议看官方文档: ...

  7. Java JDBC基础学习小结

    JDBC是一个Java应用程序接口,作用是封装了对数据库的各种操作.JDBC由类和接口组成,使用Java开发数据库应用都需要4个主要的接口:Driver.Connection.Statement.Re ...

  8. Shell基础学习小结

    0 shell基础概念 Shell是解释性语言,使用脚本编程语言的好处是,它们多半运行在比编译型语言还高的层级,能够轻易处理文件与目录之类的对象:缺点是它们的效率通常不如编译型语言.Shell命令有本 ...

  9. mongodb基础学习7-备份与恢复

    下面来讲讲mongodb的备份与恢复 备份可以备份为二进制格式,如果是用于数据交换,可以备份成json或cvs格式 导入/导出可以操作的是本地的mongodb服务器,也可以是远程的. 所以,都有如下通 ...

随机推荐

  1. 最短时间(几秒内)利用C#往SQLserver数据库一次性插入10万条数据

    用途说明: 公司要求做一个数据导入程序,要求将Excel数据,大批量的导入到数据库中,尽量少的访问数据库,高性能的对数据库进行存储.于是在网上进行查找,发现了一个比较好的解决方案,就是采用SqlBul ...

  2. [视频教程]利用SSH隧道进行远程腾讯云服务器项目xdebug调试

    我的远程服务器是腾讯云的ubuntu系统机器,本地我的电脑系统是deepin的系统,使用的IDE是vscode.现在就来使用本地的IDE来调试腾讯云中为网站项目实现逻辑是访问网站域名后,请求被转发给腾 ...

  3. openssl rsa加密,解密以及X509证书的使用

    Openssl的相关使用 生成证书 生成证书见:使用 openssl 生成证书 代码实现 Cert.h #ifndef _CERT_H #define _CERT_H ///header files ...

  4. 爬虫---lxml爬取博客文章

    上一篇大概写了下lxml的用法,今天我们通过案例来实践,爬取我的博客博客并保存在本地 爬取博客园博客 爬取思路: 1.首先找到需要爬取的博客园地址 2.解析博客园地址 # coding:utf-8 i ...

  5. SpringMVC环境搭建(二)

    一.基于XML 1. 创建Maven Project,选择war,修改pom.xml SpringMVC是依赖于Spring的,需要导入核心包. <properties> <!-- ...

  6. MySQL 行溢出数据

    MySQL 行溢出数据 MySQL 对一条记录占用的最大储存空间是有限制的,除了 BLOB 和 TEXT 类型之外,其他所有列 (不包括隐藏列和记录头信息) 占用的字节长度不能超过 65535 个字节 ...

  7. 分布式共识算法 (四) BTF算法(区块链使用)

    系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.引子 前面介绍的算法,无论是 Paxos ...

  8. Windows Azure Virtual Machine (39) 清除Linux挖矿病毒

    <Windows Azure Platform 系列文章目录> 1.之前客户遇到了Azure Linux CPU 100%,症状如下: 2.SSH登录到Linux,查看crontab,有从 ...

  9. HTML连载32-背景颜色、背景图片、背景填充

    一.背景 1.如何设置标签的背景颜色 (1)在CSS中有一个background-color:属性值:,就是专门用来设置标签的背景颜色. (2)取值:具体单词.RGB.RGBA.十六进制 例子: &l ...

  10. 【shell脚本】不停地telnet一个ip或域名,并输出结果到文件中===telnetscript.sh

    编写shell脚本不停地telnet一个域名,并输出结果到文件中 [root@localhost ~]# cat telnetscript.sh #!/bin/bash #检查是否在root用户下执行 ...