- 导航
数据库相关概念
Mongoose第三方包
启动MongoDB
创建数据库
MongoDB增删改查操作
创建文档的两种方式
mongoDB数据库导入数据
查询文档
删除文档
更新文档
mongoose验证
集合关联
MongoDB增删改查操作
用户信息增删改查
- 数据库相关概念
在一个数据库软件中可以包含多个数据仓库,在每个数据仓库中可以包含多个数据集合,每个数据集合中可以包含多条文档(具体的数据)。
database
数据库,mongoDB数据库软件中可以建立多个数据库
collection
集合,一组数据的集合,可以理解为JavaScript中的数组
document
文档,一条具体的数据,可以理解为JavaScript中的对象
field
字段,文档中的属性名称,可以理解为JavaScript中的对象属性
- Mongoose第三方包
使用Node.js操作MongoDB数据库需要依赖Node.js第三方包mongoose
使用npm install mongoose命令下载
- 启动MongoDB
在命令行工具中运行net start mongoDB即可启动MongoDB,否则MongoDB将无法连接
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
- 创建数据库
在MongoDB中不需要显式创建数据库,如果正在使用的数据库不存在,MongoDB会自动创建。
- MongoDB增删改查操作
创建集合
创建集合分为两步,一是对对集合设定规则,二是创建集合,创建mongoose.Schema构造函数的实例即可创建集合。
创建文档
创建文档实际上就是向集合中插入数据。
分为两步:
1.创建集合实例。
2.调用实例对象下的save方法将数据保存到数据库中。
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
// 创建集合规则
const courseSchema = new mongoose.Schema({
name: String,
author: String,
isPublished: Boolean
});
// 使用规则创建集合
// 1.集合名称
// 2.集合规则
const Course = mongoose.model('Course', courseSchema) // courses
// 创建文档
const course = new Course({
name: 'node.js基础',
author: '黑马讲师',
isPublished: true
});
// 将文档插入到数据库中
course.save();
- 创建文档的两种方式
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
// 创建集合规则
const courseSchema = new mongoose.Schema({
name: String,
author: String,
isPublished: Boolean
});
// 使用规则创建集合
// 1.集合名称
// 2.集合规则
const Course = mongoose.model('Course', courseSchema) // courses
// 向集合中插入文档
// Course.create({name: 'Javascript', author: '黑马讲师', isPublished: false}, (err, result) => {
// console.log(err)
// console.log(result)
// })
Course.create({name: 'Javascript123', author: '黑马讲师', isPublished: false})
.then(result => {
console.log(result)
})
- mongoDB数据库导入数据
mongoimport –d 数据库名称 –c 集合名称 –file 要导入的数据文件
找到mongodb数据库的安装目录,将安装目录下的bin目录放置在环境变量中。
- 查询文档
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
// 创建集合规则
const userSchema = new mongoose.Schema({
name: String,
age: Number,
email: String,
password: String,
hobbies: [String]
});
// 使用规则创建集合
const User = mongoose.model('User', userSchema);
// 查询用户集合中的所有文档
// User.find().then(result => console.log(result));
// 通过_id字段查找文档
// User.find({_id: '5c09f267aeb04b22f8460968'}).then(result => console.log(result))
// findOne方法返回一条文档 默认返回当前集合中的第一条文档
// User.findOne({name: '李四'}).then(result => console.log(result))
// 查询用户集合中年龄字段大于20并且小于40的文档
// User.find({age: {$gt: 20, $lt: 40}}).then(result => console.log(result))
// 查询用户集合中hobbies字段值包含足球的文档
// User.find({hobbies: {$in: ['足球']}}).then(result => console.log(result))
// 选择要查询的字段
// User.find().select('name email -_id').then(result => console.log(result))
// 根据年龄字段进行升序排列
// User.find().sort('age').then(result => console.log(result))
// 根据年龄字段进行降序排列
// User.find().sort('-age').then(result => console.log(result))
// 查询文档跳过前两条结果 限制显示3条结果
User.find().skip(2).limit(3).then(result => console.log(result))
- 删除文档
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
// 创建集合规则
const userSchema = new mongoose.Schema({
name: String,
age: Number,
email: String,
password: String,
hobbies: [String]
});
// 使用规则创建集合
const User = mongoose.model('User', userSchema);
// 查找到一条文档并且删除
// 返回删除的文档
// 如何查询条件匹配了多个文档 那么将会删除第一个匹配的文档
// User.findOneAndDelete({_id: '5c09f267aeb04b22f8460968'}).then(result => console.log(result))
// 删除多条文档
User.deleteMany({}).then(result => console.log(result))
- 更新文档
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
// 创建集合规则
const userSchema = new mongoose.Schema({
name: String,
age: Number,
email: String,
password: String,
hobbies: [String]
});
// 使用规则创建集合
const User = mongoose.model('User', userSchema);
// 找到要删除的文档并且删除
// 返回是否删除成功的对象
// 如果匹配了多条文档, 只会删除匹配成功的第一条文档
// User.updateOne({name: '李四'}, {age: 120, name: '李狗蛋'}).then(result => console.log(result))
// 找到要删除的文档并且删除
User.updateMany({}, {age: 300}).then(result => console.log(result))
- mongoose验证
required: true 必传字段
minlength:3 字符串最小长度
maxlength: 20 字符串最大长度
min: 2 数值最小为2
max: 100 数值最大为100
enum: ['html', 'css', 'javascript', 'node.js']
trim: true 去除字符串两边的空格
validate: 自定义验证器
default: 默认值
获取错误信息:error.errors['字段名称'].message
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
const postSchema = new mongoose.Schema({
title: {
type: String,
// 必选字段
required: [true, '请传入文章标题'],
// 字符串的最小长度
minlength: [2, '文章长度不能小于2'],
// 字符串的最大长度
maxlength: [5, '文章长度最大不能超过5'],
// 去除字符串两边的空格
trim: true
},
age: {
type: Number,
// 数字的最小范围
min: 18,
// 数字的最大范围
max: 100
},
publishDate: {
type: Date,
// 默认值
default: Date.now
},
category: {
type: String,
// 枚举 列举出当前字段可以拥有的值
enum: {
values: ['html', 'css', 'javascript', 'node.js'],
message: '分类名称要在一定的范围内才可以'
}
},
author: {
type: String,
validate: {
validator: v => {
// 返回布尔值
// true 验证成功
// false 验证失败
// v 要验证的值
return v && v.length > 4
},
// 自定义错误信息
message: '传入的值不符合验证规则'
}
}
});
const Post = mongoose.model('Post', postSchema);
Post.create({title:'aa', age: 60, category: 'java', author: 'bd'})
.then(result => console.log(result))
.catch(error => {
// 获取错误信息对象
const err = error.errors;
// 循环错误信息对象
for (var attr in err) {
// 将错误信息打印到控制台中
console.log(err[attr]['message']);
}
})
- 集合关联
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
const postSchema = new mongoose.Schema({
title: {
type: String,
// 必选字段
required: [true, '请传入文章标题'],
// 字符串的最小长度
minlength: [2, '文章长度不能小于2'],
// 字符串的最大长度
maxlength: [5, '文章长度最大不能超过5'],
// 去除字符串两边的空格
trim: true
},
age: {
type: Number,
// 数字的最小范围
min: 18,
// 数字的最大范围
max: 100
},
publishDate: {
type: Date,
// 默认值
default: Date.now
},
category: {
type: String,
// 枚举 列举出当前字段可以拥有的值
enum: {
values: ['html', 'css', 'javascript', 'node.js'],
message: '分类名称要在一定的范围内才可以'
}
},
author: {
type: String,
validate: {
validator: v => {
// 返回布尔值
// true 验证成功
// false 验证失败
// v 要验证的值
return v && v.length > 4
},
// 自定义错误信息
message: '传入的值不符合验证规则'
}
}
});
const Post = mongoose.model('Post', postSchema);
Post.create({title:'aa', age: 60, category: 'java', author: 'bd'})
.then(result => console.log(result))
.catch(error => {
// 获取错误信息对象
const err = error.errors;
// 循环错误信息对象
for (var attr in err) {
// 将错误信息打印到控制台中
console.log(err[attr]['message']);
}
})
- MongoDB增删改查操作
- 用户信息增删改查
// 搭建网站服务器,实现客户端与服务器端的通信
// 连接数据库,创建用户集合,向集合中插入文档
// 当用户访问/list时,将所有用户信息查询出来
// 实现路由功能
// 呈现用户列表页面
// 从数据库中查询用户信息 将用户信息展示在列表中
// 将用户信息和表格HTML进行拼接并将拼接结果响应回客户端
// 当用户访问/add时,呈现表单页面,并实现添加用户信息功能
// 当用户访问/modify时,呈现修改页面,并实现修改用户信息功能
// 修改用户信息分为两大步骤
// 1.增加页面路由 呈现页面
// 1.在点击修改按钮的时候 将用户ID传递到当前页面
// 2.从数据库中查询当前用户信息 将用户信息展示到页面中
// 2.实现用户修改功能
// 1.指定表单的提交地址以及请求方式
// 2.接受客户端传递过来的修改信息 找到用户 将用户信息更改为最新的
// 当用户访问/delete时,实现用户删除功能
const http = require('http');
const url = require('url');
const querystring = require('querystring');
require('./model/index.js');
const User = require('./model/user');
// 创建服务器
const app = http.createServer();
// 为服务器对象添加请求事件
app.on('request', async (req, res) => {
// 请求方式
const method = req.method;
// 请求地址
const { pathname, query } = url.parse(req.url, true);
if (method == 'GET') {
// 呈现用户列表页面
if (pathname == '/list') {
// 查询用户信息
let users = await User.find();
// html字符串
let list = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h6>
<a href="/add" class="btn btn-primary">添加用户</a>
</h6>
<table class="table table-striped table-bordered">
<tr>
<td>用户名</td>
<td>年龄</td>
<td>爱好</td>
<td>邮箱</td>
<td>操作</td>
</tr>
`;
// 对数据进行循环操作
users.forEach(item => {
list += `
<tr>
<td>${item.name}</td>
<td>${item.age}</td>
<td>
`;
item.hobbies.forEach(item => {
list += `<span>${item}</span>`;
})
list += `</td>
<td>${item.email}</td>
<td>
<a href="/remove?id=${item._id}" class="btn btn-danger btn-xs">删除</a>
<a href="/modify?id=${item._id}" class="btn btn-success btn-xs">修改</a>
</td>
</tr>`;
});
list += `
</table>
</div>
</body>
</html>
`;
res.end(list);
}else if (pathname == '/add') {
// 呈现添加用户表单页面
let add = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h3>添加用户</h3>
<form method="post" action="/add">
<div class="form-group">
<label>用户名</label>
<input name="name" type="text" class="form-control" placeholder="请填写用户名">
</div>
<div class="form-group">
<label>密码</label>
<input name="password" type="password" class="form-control" placeholder="请输入密码">
</div>
<div class="form-group">
<label>年龄</label>
<input name="age" type="text" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>邮箱</label>
<input name="email" type="email" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>请选择爱好</label>
<div>
<label class="checkbox-inline">
<input type="checkbox" value="足球" name="hobbies"> 足球
</label>
<label class="checkbox-inline">
<input type="checkbox" value="篮球" name="hobbies"> 篮球
</label>
<label class="checkbox-inline">
<input type="checkbox" value="橄榄球" name="hobbies"> 橄榄球
</label>
<label class="checkbox-inline">
<input type="checkbox" value="敲代码" name="hobbies"> 敲代码
</label>
<label class="checkbox-inline">
<input type="checkbox" value="抽烟" name="hobbies"> 抽烟
</label>
<label class="checkbox-inline">
<input type="checkbox" value="喝酒" name="hobbies"> 喝酒
</label>
<label class="checkbox-inline">
<input type="checkbox" value="烫头" name="hobbies"> 烫头
</label>
</div>
</div>
<button type="submit" class="btn btn-primary">添加用户</button>
</form>
</div>
</body>
</html>
`;
res.end(add)
}else if (pathname == '/modify') {
let user = await User.findOne({_id: query.id});
let hobbies = ['足球', '篮球', '橄榄球', '敲代码', '抽烟', '喝酒', '烫头', '吃饭', '睡觉', '打豆豆']
console.log(user)
// 呈现修改用户表单页面
let modify = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h3>修改用户</h3>
<form method="post" action="/modify?id=${user._id}">
<div class="form-group">
<label>用户名</label>
<input value="${user.name}" name="name" type="text" class="form-control" placeholder="请填写用户名">
</div>
<div class="form-group">
<label>密码</label>
<input value="${user.password}" name="password" type="password" class="form-control" placeholder="请输入密码">
</div>
<div class="form-group">
<label>年龄</label>
<input value="${user.age}" name="age" type="text" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>邮箱</label>
<input value="${user.email}" name="email" type="email" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>请选择爱好</label>
<div>
`;
hobbies.forEach(item => {
// 判断当前循环项在不在用户的爱好数据组
let isHobby = user.hobbies.includes(item);
if (isHobby) {
modify += `
<label class="checkbox-inline">
<input type="checkbox" value="${item}" name="hobbies" checked> ${item}
</label>
`
}else {
modify += `
<label class="checkbox-inline">
<input type="checkbox" value="${item}" name="hobbies"> ${item}
</label>
`
}
})
modify += `
</div>
</div>
<button type="submit" class="btn btn-primary">修改用户</button>
</form>
</div>
</body>
</html>
`;
res.end(modify)
}else if (pathname == '/remove') {
// res.end(query.id)
await User.findOneAndDelete({_id: query.id});
res.writeHead(301, {
Location: '/list'
});
res.end();
}
}else if (method == 'POST') {
// 用户添加功能
if (pathname == '/add') {
// 接受用户提交的信息
let formData = '';
// 接受post参数
req.on('data', param => {
formData += param;
})
// post参数接受完毕
req.on('end', async () => {
let user = querystring.parse(formData)
// 将用户提交的信息添加到数据库中
await User.create(user);
// 301代表重定向
// location 跳转地址
res.writeHead(301, {
Location: '/list'
});
res.end();
})
}else if (pathname == '/modify') {
// 接受用户提交的信息
let formData = '';
// 接受post参数
req.on('data', param => {
formData += param;
})
// post参数接受完毕
req.on('end', async () => {
let user = querystring.parse(formData)
// 将用户提交的信息添加到数据库中
await User.updateOne({_id: query.id}, user);
// 301代表重定向
// location 跳转地址
res.writeHead(301, {
Location: '/list'
});
res.end();
})
}
}
});
// 监听端口
app.listen(3000);
- index.js
const mongoose = require('mongoose');
// 数据库连接 27017是mongodb数据库的默认端口
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true })
.then(() => console.log('数据库连接成功'))
.catch(() => console.log('数据库连接失败'));
user.js
const mongoose = require('mongoose');
// 创建用户集合规则
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 20
},
age: {
type: Number,
min: 18,
max: 80
},
password: String,
email: String,
hobbies: [ String ]
});
// 创建集合 返回集合构造函数
const User = mongoose.model('User', userSchema);
module.exports = User;
- mongoDB
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 Nosql 技术门类 redis 内存型 mongodb 文档型
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
- 集群与分布式
- 基本指令
mongoDB
一、MongoDB的引言
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 Nosql 技术门类 redis 内存型 mongodb 文档型
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
二、MongoDB的特点
- 面向集合存储,易存储对象类型的数据
- 支持查询,以及动态查询
- 支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言
- 文件存储格式为BSON(一种JSON的扩展)
- 支持复制和故障恢复和分片
三、MongoDB的安装和使用
-
下载mongoDB的安装包(最新版本3.6,只能在64位系统安装)这里使用的3.0.6版本
-
上传至linux系统中解压当前的linux系统
-
将解压的文件为了方便目录进行重命名(这步可以跳过)
-
进入mongodb的文件夹中查看目录
-
在bin目录中存在大量mongodb使用的命令
- 启动mongoDB数据库服务
./mongod --port 27017 --dbpath /root/data
注意:
启动时要求存放数据的目录必须存在
默认的端口号是27017 可以通过–port 指定端口启动
- 出现如下结果代表启动成功
四、MongoDB的shell(客户端)操作
-
进入mongo的bin目录中找到如下指令
-
使用如下命令连接到mongodb的服务中
注意:
a) 连接到mongodb后,mongo和mysql数据库有点像,先是一个一个库的概念,操作之前需要先选中库
- 查看系统中默认的所有库
show dbs;
注意:
默认只有一个local库
还有一个默认隐藏不可见的数据库 admin
- 选中一个库
a) use 数据库名称
注意:
use命名 存在库使用当前库 不存在则创建当前库
- 删除一个库
db.dropDatabase();
注意: 选中那个库,删除的就是当前选中的库
- Mongodb的数据库中,库中是一个一个集合的概念,选中库后要创建一个一个的集合,集合类似于传统的关系型数据库中的表
a) 显示创建集合 db.createCollection(“t_user”);
b) 隐式创建集合 创建集合同时添加元素
-
查看mongo 中当前库
a) db 命令显示当前库 -
显示当前库中的所有集合
a) show collections; -
Mongo中插入数据
a) 向集合中插入数据
db.集合名称.insert({name:‘xiaohei’,age:23,sex:true});
b) 向集合中插入多条数据
db.集合名称.insert([{name:‘xiaohei’,age:23,sex:true},…]);
- Mongo中的删除数据
a) db.集合名称.remove({条件}) //删除满足条件的数据
b) db.集合名称.remove({不加任何条件})//删除所有文档 保留空的集合
- Mongo中的修改数据
a) db.集合名称.update({条件},{更新内容});
b) db.集合名称.update({“name”:“zhangsan”},{name:“11”,bir:new date()}) --这个更新是将符合条件的全部更新成后面的文档,相当于先删除在更新
c) db.集合名称.update({“name”:“xiaohei”},{KaTeX parse error: Expected 'EOF', got '}' at position 22: …ame:"mingming"}}̲) --保留原来的值修改…set:{name:”小明”}},{multi:true}) —保留原来数据更新,更新符合条件的所有数据
e) db.集合名称.update({name:”小黑”},{KaTeX parse error: Expected 'EOF', got '}' at position 16: set:{name:”小明”}}̲,{multi:true,up…inc:{age:1}},{upsert:true,multi:true}) --在保留原始数据同时给符合条件的所有age这列的值自增指定的大小
g)
- 删除集合
a) db.集合名称.drop();
- 查询集合
a) db.集合名称.find();
b) db.集合名称.find({条件})
c) db.集合名称.find({条件},{显示字段,name:1,age:1}) 1 显示 0 不显示 1和0 不能混合出现
d) 查询结果排序:db.集合名称.find().sort({条件name:1,age:1}), 1 升序 -1 降序
e) 分页查询:db.集合名称.find().sort({条件}).skip(起始条数).limit(显示总记录数);
f) 总条数:db.集合名称.count();|db.t_user.find({“name”:“aa”}).count();
g) 模糊查询:使用正则表达式db.集合名称.find({“name”:/go/})
h) 等值(==)查询
db.user.find({name:“张三”});
db.user.find({name:{KaTeX parse error: Expected 'EOF', got '}' at position 8: eq:"张三"}̲}); i) 且 (and) 查询
db.t_user.find({name:“zhangsan”,age:12});
db.t_user.find({$and:[{name:“zhangsan”},{id:10}]})
j) $or使用:
i.
db.集合名称.find({
KaTeX parse error: Expected '}', got 'EOF' at end of input: …y:value},{age:{gte:20}}
]
});
k) $gt大于 $gte大于等于 $lt 小于 $lte 小于等于 KaTeX parse error: Expected '}', got 'EOF' at end of input: ….find({“age”:{“lte”:18,”$gte”:30}})
l) KaTeX parse error: Expected '}', got 'EOF' at end of input: …b.t_user.find({nor:[{name:“chenyn”},{age:26}]});
- shell非正常关闭时,下次无法连接问题解决方案:
i. 删除数据目录中的mongo.lock文件即可
五、Java操作mongoDB
-
项目中引入mongo的坐标
-
使用java操作mongo
a) 参见代码 mongo-java
六、Spring Boot整合mongoDB
- pom配置
pom包里面添加spring-boot-starter-data-mongodb包引用
- 在application.properties中添加配置
spring.data.mongodb.uri=mongodb://localhost:27017/test- 详细操作参见springboot-mongo
七、MongoDB中的索引
索引就是为了加速查询的,MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧。下面是创建索引的命令:
1. 创建索引:db.集合名称.ensureIndex({"name":1})
a) 1 代表索引升序存储 -1 代表索引降序存储
b) _id 默认自动创建索引
2. 创建索引指定索引名称:db.集合名称.ensureIndex({"name":1},{name:"name_index"})
3. 查看索引是否创建成功:db.集合名称.getIndexes()
4. 删除索引的命令:db.集合名称.dropIndex({"name":1});
5. 创建复合索引:db.集合名称.ensureIndex({"name":1, "age":-1,bir:1})
a) 注意:
i. 该索引被创建后,基于name和age的查询将会用到该索引
ii. 或者是基于name的查询也会用到该索引
iii. 但是只是基于age的查询将不会用到该复合索引。
b) 总结:
i. 如果想用到复合索引,必须在查询条件中包含复合索引中的前N个索引列。然而如果查询条件中的键值顺序和复合索引中的创建顺序不一致的话,MongoDB可以智能的帮助我们调整该顺序,以便使复合索引可以为查询所用。
ii. 如:db.t_user.find({"age": 30, "name": "stephen"})
对于上面示例中的查询条件,MongoDB在检索之前将会动态的调整查询条件文档的顺序,以使该查询可以用到刚刚创建的复合索引。
6. 创建唯一索引:db.t_user.ensureIndex({"name":1},{"unique":true})
注意: 在缺省情况下创建的索引均不是唯一索引。一旦创建唯一索引, 如果再次插入name重复的文档时,MongoDB将报错,以提示插入重复键 (exception: E11000 duplicate key error index: zpark.t_user.$name_1 dup key: { : \"xiaohei\" })
7. 重建索引:db.集合名称.reIndex();
八、mongoDB中的主从复制(4.0版本废弃)
主从复制是mongoDB最常用的复制方式,这种方式非常灵活,可用于备份,故障恢复和扩展等.
1. 搭建主从复制
a) 准备三个机器一个主机两个备机
mongod --port 27017 --dbpath /root/data/master/ --bind_ip 0.0.0.0 --master --oplogSize 50
mongod --port 27018 --dbpath /root/data/slave1 --bind_ip 0.0.0.0 --slave --source 172.16.19.137:27017 --only baizhi –autoresync
mongod --dbpath /root/data/slave2 --port 27019 --bind_ip 0.0.0.0 --slave --source 172.16.19.137:27017 --only baizhi --autoresync --slavedelay 30
2. 主从复制的选项
--master 主节点
--slave 从节点
--source arg 为从节点时从哪个主节点复制<server:port>
--only arg 为从节点时只复制主节点的那个库
--slavedelay arg 从节点延迟多长时间复制主节点 秒
--autoresync 从机数据不是最新是自动重新同步数据
--oplogSize 主节点的操作日志单位是M
3. 查看集群状态:
rs.help();
rs.slaveOk(); //开启从机查询
九、MongoDB中的副本集
MongoDB 副本集(Replica Set)是有自动故障恢复功能的主从集群,有一个Primary节点和一个或多个Secondary节点组成。主从集群和副本集之间最明显的区别就是副本集没有固定的”主节点”,
整个集群会选举一个主节点,当主节点不能工作时自动变更到其他节点.
1. 配置主机名
a) vi /etc/hosts文件加入如下配置
i. 当前主机地址 mongo
2. 搭建副本集
a) 准备三个存放数据的目录并启动三个节点
mongod --port 27017 --dbpath /root/repl1 --bind_ip 0.0.0.0 --replSet myreplace/mongo:27018
mongod --port 27018 --dbpath /root/repl2 --bind_ip 0.0.0.0 --replSet myreplace/mongo:27019
mongod --port 27019 --dbpath /root/repl3 --bind_ip 0.0.0.0 --replSet myreplace/mongo:27017
注意: --replSet 副本集 myreplace 副本集名称/集群中其他节点的主机和端口
b) 连接任意一台mongo
i. use admin
ii. 执行如下命令
var config = {
_id:"myreplace",
members:[
{_id:0,host:"mongo:27017"},
{_id:1,host:"mongo:27018"},
{_id:2,host:"mongo:27019"}]
}
rs.initiate(config);//初始化配置
c) 设置客户端临时访问数据:rs.slaveOk();
Springboot 操作副本集
spring.data.mongodb.uri=mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/ems(库名)?replcaSet=spock(副本集名称)
十、Mongodb中的分片
- 分片(sharding)
分片目的是通过分片能够增加更多机器来应对不断的增加负载和数据,还不影响应用.
分片(sharding)是指将数据拆分,将其分散存在不同机器的过程,有时也用分区(partitioning)来表示这个概念,将数据分散在不同的机器上,不需要功能强大的大型计算机就能存储更多的数据,处理更大的负载.
MongoDB支持自动分片,可以摆脱手动分片的管理困扰,集群自动切分数据做负载均衡.MongoDB分片的基本思想就是将集合拆分成多个块,这些快分散在若干个片里,每个片只负责总数据的一部分,应用程序不必知道哪些片对应哪些数据,甚至不需要知道数据拆分了,所以在分片之前会运行一个路由进程,mongos进程,这个路由器知道所有的数据存放位置,应用只需要直接与mongos交互即可,mongos自动将请求转到相应的片上获取数据.从应用角度看分不分片没有什么区别.- 什么时候分片
a) 机器磁盘不够用了
b) 单个的mongo已经不能满足写数据的性能需要了- mongoDB的分片架构图
- 片键
设置分片时需要在集合中选一个键,用该键的值作为拆分数据的依据,这个片键称之为(shard key)
注意: 在真正的生产环境中,片键的选取很重要,片键的选取要一定要数据散列均匀- 搭建分片集群
a) 分片结构的端口如下
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Config Server :27101
Config Server :27102
Route Process:40000
b) 创建数据目录
mkdir -p /root/shard/s0
mkdir -p /root/shard/s1
mkdir -p /root/shard/s2
mkdir -p /root/shard/s3
mkdir -p /root/shard/config1
mkdir -p /root/shard/config2
mkdir -p /root/shard/config3
c) 创建数据目录并启动四台shard机器
mongod --port 27020 --dbpath /root/shard/s0 --bind_ip 0.0.0.0 --shardsvr
mongod --port 27021 --dbpath /root/shard/s1 --bind_ip 0.0.0.0 --shardsvr
mongod --port 27022 --dbpath /root/shard/s2 --bind_ip 0.0.0.0 --shardsvr
mongod --port 27023 --dbpath /root/shard/s3 --bind_ip 0.0.0.0 --shardsvr
d) 创建config数据目录启动配置机器
mongod --port 27100 --dbpath /root/shard/config1 --bind_ip 0.0.0.0 --replSet config/mongo:27101 --configsvr
mongod --port 27101 --dbpath /root/shard/config2 --bind_ip 0.0.0.0 --replSet config/mongo:27102 --configsvr
mongod --port 27102 --dbpath /root/shard/config3 --bind_ip 0.0.0.0 --replSet config/mongo:27100 --configsvr
e) 初始化config的配置服务器副本集
i. 登录任意config的server节点中使用 use admin
ii. config在admin中执行
var config = {
_id:“config”,
configsvr: true,
members:[
{_id:0,host:“mongo:27100”},
{_id:1,host:“mongo:27101”},
{_id:2,host:“mongo:27102”}]
}
iii. 初始化副本集配置 rs.initiate(config);
f) 启动路由
i. mongos --port 40000 --configdb config/mongo:27100,mongo:27101,mongo:27102 --bind_ip 0.0.0.0
注意: config为上面的副本集名称
g) 客户端登陆到mongos中 mongo –port 40000
i. use admin
ii. 添加分片节点:
db.runCommand({ addshard:“mongo:27020”,“allowLocal”:true });
db.runCommand({ addshard:“mongo:27021”,“allowLocal”:true });
db.runCommand({ addshard:“mongo:27022”,“allowLocal”:true });
db.runCommand({ addshard:“mongo:27023”,“allowLocal”:true });
h) 设置分片的库:db.runCommand({ enablesharding:“baizhi” });
i) 设置那个库中那个集合以及片键信息:
db.runCommand({ shardcollection: “baizhi.users”, key: { _id:1}})
db.runCommand({ shardcollection: “baizhi.users”, key: { _id: “hashed”}})