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

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

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

不适用的场景如下:
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,某些命令会不同。
// 上传/解压/
unzip mongo*.zip
cd mongo*

// 使用CPU多核加速编译 本例是4核
scons all -j 4

//------------------ 若编译不成功, 建议还是到官网下载bin 注意选择OS版本
// https://www.mongodb.com/download-center

// 上传mongodb-linux-x86_64-3.6.4.tgz 到 /home/
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

 

// 启动服务    指定路径       --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  // centos 6.5 
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

// ---------------------------另一种以前的配置文件书写方式--------------------------

Mongodb学习小结 Nosql 第1张
    // 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

    // how the process runs
    processManagement:
      fork: true  // fork and run in background
      pidFilePath: /opt/mongodb/mongod.pid  // location of pidfile

    // network interfaces
    net:
      port: 27017
      bindIp: 0.0.0.0  // Listen to local interface only, comment to listen on all interfaces.

    security:
      authorization: "enabled"  
View Code

 

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

 

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

 

//###########################  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" 

    
// Shell 常用操作
    db
    show dbs 
    show collections 
    use local 
    show users  // 查看当前库中用户
    db.test.insert({'a':'333323'}) // 插入数据时会自动创建库和Collections
    db.test.find()  // 显示所有数据
    
    exit    // 退出mongo shell
    
// 最后用Robo 3T 测试连接

 

/*************** 如果需要重置密码: ***************/
//  1. 停止服务
//  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
***********/

    // 例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:100000,max:5})

db.sub.isCapped() // 检查是否 capped

// 转换为 capped 集合
db.runCommand({"convertToCapped": "test", size: 100000, max:10 });

 

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

//----------------------------------- 增 ---------------------------------------
// 插入多条
db.users.insert([
    {name:'Allan',age:32,gender:1},
    {name:'Bob',age:25,gender:1},
    {name:'Celine',age:32,gender:2},
    {name:'Dennis',age:12,gender:1},
])

// 以下两种插入方法是为了语义清晰
// 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:25}})  // 条件数量
db.test.find({age:{$gt:25}})    // 大于
db.test.find({age:{$eq:25}})    // 等于
db.test.find({age:{$lt:25}})    // 小于
db.test.find({age:{$gt:20, $lt:30}})                     // 大于且小于
db.demoes.find({$or:[{num:{$lt:10}},{num:{$gt:1990}}]})  // 或 $or:[{},{},]
db.users.find({age:{$in:[25,32]}})                       // 在in 或 不在nin
db.users.find({name:/^C/})              // 正则,以C开头
db.users.find({name:{$regex:"^A"}})     // 正则, 以A开头

// 虽然可用JS语法,但是效率低
db.users.find({$where:function(){return this.age>20}})  
db.users.find({$where:function(){return this.name.startsWith("C")}})

db.test.find().limit(10)                // 前10条
db.test.find().skip(10).limit(10)       // 跳过10条

// skip( (页码 -1) * 每页条数).limit(每页条数)
// limit()与skip()或sort() 前后无关,mongodb自动调整

db.test.find().sort({age:-1})           // 按年龄降序 

// 1取0不要,只有_id需要特别指定为0
db.test.find({},{name:1, _id:0, age:1})         // 投影:只要name和age,不要_id
db.users.distinct("gender", {age:{$lt:20}})     // 年龄小于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:88}}) 
db.test.update({_id:ObjectId("5cede5d81f3b03073319abd0")},{$unset:{address:0}})  // 删除

db.test.update({name:"AAAA"},{$set:{address:"test"}})       // 默认只改一条
db.test.update({name:"AAAA"},{$set:{address:"999"}},{multi:true})  // 使用multi改所有的

db.test.updateMany({name:"AAAA"},{$set:{address:"105"}})   // 改所有符合的

 
/* ********************************* 删 ****************************************/
db.test.remove({address:"999"})     // 默认删除全部匹配的
db.test.remove({address:"999"}, true)    // 只删除一个
db.test.remove({},true)    // 删除第一个
db.test.remove({})         // 清空集合 

db.test.drop()     // 删除集合
db.dropDatabase()  // 删当前库(赶紧跑路)

// 通常上面的都不会执行, 使用字段isDel代替
db.test.updateOne({name:"AAAA"},{$set:{isDel:1}})  
db.test.find({isDel:0})

 

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

// 属性值也可以是个文档 即 内嵌文档
db.goods.update({name:"CPU"},{$set:{band:{Intel:["I3","I5","I7"],AMD:["R5","R7"]}}})
db.goods.find({'band.AMD':'R5'})   // 查询内嵌时必须引号, 包含

db.goods.update({name:"Mem"},{$push:{'band.KST':'3333'}})     // 插入一个,可重复
db.goods.update({name:"Mem"},{$addToSet:{'band.KST':'3333'}}) // 添加到集合,不重复
db.goods.update({name:"Mem"},{$pop:{'band.KST':1}})           // 移除最后一个元素

//# 插入20000条数据
 // 1. 笨方法:
    for(var i=1; i<20001;i++){
           db.demos.insert({num:i})
    }
    
 // 2. 好方法:
    var arr=[];
    for(var i=1; i<20001;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:"如来"})[0]._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:1000}},{$inc:{sal:400}})
db.emp.updateMany({deptno:2},{$inc:{sal:500}})   // IT部加工资

// 3. 价高于300的减100
db.goods.updateMany({price:{$gt:300}},{$inc:{price:-100}})

 

管道

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

// 各求男女人数
db.users.aggregate([{$group:{_id:'$gender',counter:{$sum:1}}}])

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:25}}}])    // 筛选

// 将筛选后的结果再聚合
db.users.aggregate([
    {$match:{age:{$gt:25}}},
    {$group:{_id:'$gender',counter:{$sum:1}}}
])                                       

// 筛选,聚合,投影
db.users.aggregate([
    {$match:{age:{$gt:25}}},
    {$group:{_id:'$gender',counter:{$push:'$name'}}},
    {$project:{_id:0,counter:1}}
])

// 排序,和find()中的几乎一样 {$sort:{_id: -1}} 也可以用在多个地方
db.users.aggregate([
    {$match:{age:{$gt:25}}},
    {$sort:{name: 1}}, 
    {$group:{_id:'$gender',counter:{$push:'$name'}}},
    {$sort:{_id:-1}}
])    // 内按name升序,外按_id降序

// 跳过 {$skip:10},限制{$limit:5} 此处区分顺序

/**  
* {$unwind:"$counter"} 将数组字段拆开成单条 
*/
db.students.aggregate([
    {$match:{name:"WuKong"}},
    {$unwind:"$teacher_ids"}
])

db.t3.insert([
    {"_id":1,"item":"a","size":["S","M","L"]},
    {"_id":2,"item":"b","size":[]},
    {"_id":3,"item":"c","size":"M"},
    {"_id":4,"item":"d"},
    {"_id":5,"item":"e","size":null},
])

db.t3.aggregate([{$unwind:{path:"$size"}}])  // 取出值 不含空和null以及无字段

// 取出值,不丢任何数据
db.t3.aggregate([
    {$unwind:{path:"$size", preserveNullAndEmptyArrays:true}}
])

 

索引

/********************************** 索引 **************************************/
db.t1.ensureIndex({name:1})                  // 添加索引
db.t1.ensureIndex({name:1}, {unique:true})  // 多参数
db.t1.ensureIndex({name:1,age:1})           // 联合索引
db.t1.getIndexes()                          // 查询索引
db.t1.dropIndex("name_1")                   // 删除指定索引
db.t1.dropIndexes()                         // 删除全部索引,保留默认 _id_ 索引

// 测试数据
let arr=[];
for(let i=0;i<50000;i++){
    arr.push({name:"test"+i, age:i});
}
db.t1.insert(arr)

// 性能评估   其中结果 executionTimeMillis 为毫秒
db.t1.find({name:'test9999'}).explain('executionStats')

db.t1.ensureIndex({name:1}) // 添加索引

// 再次执行 结果 executionTimeMillis 降低很多
db.t1.find({name:'test9999'}).explain('executionStats')

 

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

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

// 例1:单机演示。(生产环境不适用)使用不同端口,不同数据目录,必须设置相同 replSet
    mongod --bind_ip 192.168.112.9 --port 27018 --dbpath /data/t1 --replSet rs0
    mongod --bind_ip 192.168.112.9 --port 27019 --dbpath /data/t2 --replSet rs0
    // 服务运行窗口可以看到后续操作的日志显示

    // 然后客户端分别连接服务
    mongo --host 192.168.112.9 --port 27018
    mongo --host 192.168.112.9 --port 27019
    
    rs.initiate()   // 初始化为master 提示符发生变化 
    rs.status()     // 查看复制集状态  rs0:PRIMARY>
    rs.add("192.168.112.9:27019")  // 添加slave

    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 27018 --dbpath /data/t3 --replSet rs1
    mongod --bind_ip 192.168.112.9 --port 27018 --dbpath /data/t3 --replSet rs1

    // 使用客户端分别连接服务
    mongo --host 192.168.112.6 --port 27018
    mongo --host 192.168.112.9 --port 27018

    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:28})
db.users.insert({name:"Bob",age:38})

// slave上查询
use demo1
db.users.find()  // 得到相同结果

// 发现master当机后,原slave则自动变为PRIMARY 
// 而master要及时启用并执行 rs.slaveOk() 切为SECONDARY 

 

备份与恢复

// 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;

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄