MongoDB

MongoDB

安装

windows

mac

  • 直接 brew install mongodb 安装时报这个错 Error: mongodb: unknown version :mountain_lion

可以如下操作:

  • brew uninstall mongodb
  • brew tap mongodb/brew
  • brew install mongodb-community

启动与连接

windows(以64位为例)

  • 将mondodb 64位绿色版下载,放到D盘/mongodb(自定义)下

  • 找到mongodb安装目录 D:\mongodb\MongoDB\bin (mongod.exe 服务端、mongo.exe 客户端)

  • 在当前文件夹下打开命令行 输入 mongod(这个代表启动当前的mongod.exe),完整如下:

    1
    2
    // ./data 表示数据存在data下
    mongod --dbpath=./data
  • 命令行最后 waiting for connections on port 27017 证明服务器启动成功

  • 新开一个命令行 (客户端窗口)

    1
    mongo

连接成功,如下图:

基本概念

  • 数据库 MongoDB的单个实例可以容纳多个独立的数据库,比如一个学生管理系统就可以对应一个数据库实例
  • 集合 数据库是由集合组成的,一个集合用来表示一个实体,如学生集合
  • 文档 集合是由文档组成的,一个文档表示一条记录,比如一位同学张三就是一个文档

基本操作

Mongoose

基本概念

  • Mongoose是MongoDB的一个对象模型工具
  • 同时它也是针对MongoDB操作的一个对象模型库,封装了MongoDB对文档的的一些增删改查等常用方法
  • 让NodeJS操作Mongodb数据库变得更加灵活简单
  • Mongoose因为封装了MongoDB对文档操作的常用方法,可以高效处理mongodb,还提供了类似Schema的功能,如hook、plugin、virtual、populate等机制。
  • 官网 mongoosejs

使用mongoose

安装mongoose

1
npm install mongoose

使用mongoose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// connection.js
//引入mongoose模块
let mongoose = require('mongoose');
//创建对数据库的连接
let conn = mongoose.createConnection(
'mongodb://127.0.0.1:27017/cms',
{
useNewUrlParser: true, //使用新的url解析器
useUnifiedTopology: true
}
);
conn.on('open',()=>{
console.log('当mongoose成功连接数据库之后会打印这个日志')
});
conn.on('error',(error)=>{
console.log('如果说连接失败了,会把失败的原因传递给',error)
});
module.exports = conn;

运行: node connection.js, 连接成功

使用客户端 Robo 3T

新建 连接

Schema

  • Schema是数据库集合的模型骨架
  • 定义了集合中的字段的名称和类型以及默认值等信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 定义schema
var personSchema = new Schema({
name:String, //姓名
binary:Buffer,//二进制
living:Boolean,//是否活着
birthday:Date,//生日
age:Number,//年龄
_id:Schema.Types.ObjectId, //主键
_fk:Schema.Types.ObjectId, //外键
array:[],//数组
arrOfString:[String],//字符串数组
arrOfNumber:[Number],//数字数组
arrOfDate:[Date],//日期数组
arrOfBuffer:[Buffer],//Buffer数组
arrOfBoolean:[Boolean],//布尔值数组
arrOfObjectId:[Schema.Types.ObjectId]//对象ID数组
nested:{ name:String} //内嵌文档
});

let p = new Person();
p.name= 'jfhh';
p.age = 25;
p.birthday = new Date();
p.married = false;
p.mixed= {any:{other:'other'}};
p._otherId = new mongoose.Types.ObjectId;
p.hobby.push('smoking');
p.ofString.push('string');
p.ofNumber.pop(3);
p.ofDates.addToSet(new Date);
p.ofBuffer.pop();
p.ofMixed = ['anything',3,{name:'jfhh'}];
p.nested.name = 'jfhh';
使用schema
1
2
3
4
5
6
7
8
let mongoose = require('mongoose');
let connection = require('./connection');
//定义Schema 对应的是集合,或者说是集合中的文档
let UserSchema = new mongoose.Schema({
name:String,
age:Number
});
//Schema是与数据无关的,并不能直接操作数据库

Model

Model是由通过Schema构造而成 除了具有Schema定义的数据库骨架以外,还可以操作数据库 如何通过Schema来创建Model呢,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let mongoose = require('mongoose');
let connection = require('./connection');
let UserSchema = new mongoose.Schema({
name:String,
age:Number
});
//Model 模型 User是模型 的名字,以后可以通过这个名字来引用这个模型
//传二个参数表示定义模型 ,传一个参数表示引用或者说获取 这个模型 xxx.val('yyy')
//默认情况下,集合的名字是由Model的名字决定的 User->小写user->复数users
let UserModel = connection.model('User',UserSchema);
let UserModel2 = connection.model('User');
console.log(UserModel === UserModel2); // true

// 自己定义集合的名字
let UserSchema = new mongoose.Schema({
name:String,
age:Number
},{collection:'user'}); //这样就会创建一个user的集合

通过模型往数据库里面写数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let mongoose = require('mongoose');
let connection = require('./connection');
let UserSchema = new mongoose.Schema({
name:String,
age:Number
});
let UserModel = connection.model('User',UserSchema);

// 插入数据
UserModel.create({name:'jf1',age:10},(err,doc)=>{
//err是错误对象 doc是保存成功后的文档对象
console.log(err);
console.log(doc);
});
// create方法返回的是promise,所以也可以用then
UserModel.create({name:'jf',age:10}).then(result=>{
console.log(result);
},error=>{
console.log(error);
});

Entity简述

  • 通过Model创建的实体,它也可以操作数据库
  • 使用Model创建Entity,如下示例:
1
2
3
4
5
6
7
8
9
 // 一个实体就代表一个文档对象
let user1 = new UserModel({
name:'jf1',
age:10
});
// 保存到数据库 它也返回promise
user1.save().then(doc=>{
console.log(doc);
});

模型是一个总的概念,它代表整个集合,操作对象是整个集合
实体是一个单个的概念,它代表单个文档。只能操作自己

ObjectId

  • 存储在mongodb集合中的每个文档都有一个默认的主键_id
  • 这个主键名称是固定的,它可以是mongodb支持的任何数据类型,默认是ObjectId 该类型的值由系统自己生成,从某种意义上几乎不会重复
  • ObjectId使用12字节的存储空间,是一个由24个16进制数字组成的字符串(每个字节可以存储两个16进制数字)

5d9c8817a62ce21e04dc4e57

1
2
3
4
5
6
7
8
9
10
11
let _id = '5d9c8817 a62ce2 1e04 dc4e57';
let ts = '5d9c8817'; // 时间戳
console.log(parseInt(ts,'16')); // 1570539543
console.log(new Date(parseInt(ts,'16')*1000)); // 2019-10-08T12:59:03.000Z
let host = 'a62ce2';//表示当前主机 一般是主机名hash值

let pid = '1e04';
console.log(parseInt(pid,'16'));//7684 十进制数 代表当前的进程ID

let seq = 'dc4e57'; // 由一个随机数开始的计数器生成的值
console.log(parseInt(seq,'16'));//14437975

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let mongoose = require('mongoose');
let connection = require('./connection');
//定义Schema 对应的是集合,或者说是集合中的文档
let UserSchema = new mongoose.Schema({
name:String,
age:Number
},{collection:'user'}); // user集合

let UserModel = connection.model('User',UserSchema);
(async function(){
// 添加
let result = await UserModel.create({name:'jf',age:10});
// 查询全部
let docs = await UserModel.find();
// 查询条件 name=jf
// let docs = await UserModel.find({name:'jf'});
console.log(result); // { _id: 5d9ed2ab55d44e2c5cffe99f, name: 'jf', age: 10, __v: 0 }
console.log(docs); // [{},{}...]

// 更新
// 第1个参数是条件 第2个参数是更新后的值
// updateOne 如果找到了多条匹配记录,则只更新第一条
// updateMany 如果找到了多条记录,则更新所有匹配的记录
let result = await UserModel.updateMany({name:'jf'},{age:20});
// n表示匹配的条件 nModified表示实际发生更新操作的条数
console.log(result);//{ ok: 1, nModified: 0, n: 1 }

// 删除
// deleteOne 删除第一条,后面不再匹配了,更不会删除了
// deleteMany 删除所有的匹配的条数
let result = await UserModel.deleteMany({name:'jf'});
console.log(result); // { n: 4, ok: 1, deletedCount: 4 }
process.exit(0); // 退出
})();
查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
let mongoose = require('mongoose');
let connection = require('./connection');
//定义Schema 对应的是集合,或者说是集合中的文档
let UserSchema = new mongoose.Schema({
name:String,
age:Number
},{collection:'user'});

let UserModel = connection.model('User',UserSchema);
(async function(){
// 首先插入数据
let users = [];
for(let i = 1; i <= 10; i++){
users.push({name:`jf${i}`, age: i});
}
await UserModel.create(users);

//按属性过滤
let docs = await UserModel.find({name:'jf'});
console.log(docs);

//查找一条
let docs = await UserModel.findOne({});
console.log(docs);

//findById
let doc = await UserModel.findById("5d9ed808eff86c33200fdbb7");
console.log(doc);

// 大于 gt greater than小于 lt less than 大于等于 ge greater equal 小于等于 le less equal 不等于 ne not equal
let docs = await UserModel.find({"age":{"$ne":5}});
console.log(docs);

docs = await UserModel.find({"age":{"$in":[5,6,7]}});
console.log(docs);

//大于7或者 小于3
//docs = await UserModel.find({'$or':[{name:'jiafei1'},{age:5}]});
docs = await UserModel.find({"$or":[{age:{$lt:3}},{age:{$gt:7}}]});
console.log(docs);

//每页3条,查询第2页 1 2 3 4 5 6 7 8 9 10
let pageSize = 3;
let pageNumber =2;
//sort指定排序的字段和升序还是降序 1 升序 -1 降序
//skip指定跳过几条,忽略 掉几条
//limit限定返回的最大条数
// exec() 执行
let docs = await UserModel.find({}).sort({age:1}).skip((pageNumber-1)*pageSize).limit(pageSize).exec();
console.log(docs);//4 5 6
process.exit(0);
})();
populate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
let mongoose = require('mongoose');
let connection = require('./connection');
let UserSchema = new mongoose.Schema({
name:String,
age:Number
});
let User = connection.model('User',UserSchema);

let ScoreSchema = new mongoose.Schema({
//uid是一个外键,类型是ObjectId类型,引用的是User模型 nosql 不是sql not only sql
uid:{type:mongoose.Schema.Types.ObjectId,ref:'User'},
grade:Number
});
let Score = connection.model('Score',ScoreSchema);

(async function(scoreId){
let user = await User.create({name:'jf'});//先创建主表
console.log(user); // { _id: 5d9edda206d5b83260cd0564, name: 'jf', __v: 0 }

let score = await Score.create({uid:user._id,grade:100});
console.log(score); // { _id: 5d9edda306d5b83260cd0565, uid: 5d9edda206d5b83260cd0564, grade: 100, __v: 0 }

// 通过scores集合中的_id, 拿到对应的外键uid,再通过uid拿到集合users中的name
let score = await Score.findById(scoreId);
console.log(score); // { _id: 5d9edda306d5b83260cd0565, uid: 5d9edda206d5b83260cd0564, grade: 100, __v: 0 }
let user = await User.findById(score.uid);
console.log(user); // { _id: 5d9edda206d5b83260cd0564, name: 'jf', __v: 0 }
// 这样要查询2次 才能拿到用户的 name

// 使用populate
// populate就是填充的意思,就是把一个外键字段从一个ObjectId变成一个对象
let score2 = await Score.findById(scoreId).populate('uid');
console.log(score2);
// { _id: 5d9edda306d5b83260cd0565, uid: { _id: 5d9edda206d5b83260cd0564, name: 'jf', __v: 0 }, grade: 100, __v: 0 }
})('5d9edda306d5b83260cd0565');

mongodb用的非常多,像爱奇艺里面的视频,再次打开,播放记录,也是放到mongodb里面的。

参考资料:http://www.zhufengpeixun.cn/ahead/html/29.mongodb-5.html