今天继续学习,介绍下mongodb
1.mongodb的介绍
MongoDB 是一个基于分布式文件存储的数据库。
由 C++ 语言编写。
旨在为 WEB 应用提供可扩展的高性能数据存储解决方案.
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。
MongoDB 文档类似于 JSON 对象。
字段值可以包含其他文档,数组及文档数组。
1.1 关系型数据库和非关系型数据库区别
不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍。下表将帮助您更容易理解Mongo中的一些概念:
sql术语/概念 | mongodb术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,mongodb不支持 | |
primary key | primary key | 主键,mongdb自动将_id字段设置为主键 |
下表说明各自的优缺点以及特性
数据库类型 | 特性 | 优点 | 缺点 |
---|---|---|---|
关系型数据库 | 1、关系型数据库,是指采用了关系模型来组织数据的数据库;2、关系型数据库的最大特点就是事务的一致性;3、简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。 | 1、容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解;2、使用方便:通用的SQL语言使得操作关系型数据库非常方便;3、易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率;4、支持SQL,可用于复杂的查询。 | 1、为了维护一致性所付出的巨大代价就是其读写性能比较差;2、固定的表结构;3、高并发读写需求;4、海量数据的高效率读写; |
非关系型数据库 | 1、使用键值对存储数据;2、分布式;3、一般不支持ACID特性;4、非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。 | 1、无需经过sql层的解析,读写性能很高;2、基于键值对,数据没有耦合性,容易扩展;3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,而关系型数据库则只支持基础类型。 | 1、不提供sql支持,学习和使用成本较高;2、无事务处理,附加功能和报表等支持也不好; |
1.2命令行操作 Mongodb
1.2.1准备工作
D盘mongodb文件夹内解压下载好的mongodb文件
D盘根目录下创建一个文件夹data,在data内部再创建一个文件夹db
进入到mongodb的bin目录
按住shift,点击鼠标的右键,打开命令行窗口,输入如下指令打开数据库连接池
mongod --dbpath d:\data\db
再在此目录中,按住shift,点击鼠标的右键,打开命令行窗口,输入如下指令打开一个连接数据库的客户端,不要关闭上一个窗口
mongo
如果这样丛不成功,说明是管理员权限的问题,那就需要多走几步路
以管理员身份运行命令行窗口打开数据库连接池
d:
cd mongodb (注意你自己的文件夹的名称)
cd mongodb-win32-x86_64-2008plus-ssl-4.0.9
cd bin
mongod --dbpath d:\data\db
以管理员身份运行命令行窗口打开客户端
d: cd mongodb (注意你自己的文件夹的名称)
cd mongodb-win32-x86_64-2008plus-ssl-4.0.9
cd bin
mongo
1.3 数据库常用命令
1.3.1 help查看命令提示
help
db.help()
db.test.help()
db.test.find().help()
1.3.2 创建切换数据库
无则创建并且切换,有则切换
db // test
use tab// switched to db tab
db // tab
1.3.3 查询数据库
明明已经创建了数据库tab,但是查询不出来,是因为现在你的数据库是空的,admin和local数据库是系统默认的数据库
show dbs
/**
admin local
*/
1.3.4 显示当前DB状态
db.stats()
/**
{ "db" : "tab",
"collections" : 0,
"views" : 0,
"objects" : 0,
"avgObjSize" : 0,
"dataSize" : 0,
"storageSize" : 0,
"numExtents" : 0,
"indexes" : 0,
"indexSize" : 0,
"fileSize" : 0,
"ok" : 1
}
*/
1.3.5 查看当前DB版本
db.version()
/*
4.0.9
*/
1.3.6 查看当前DB的连接机器地址
db.getMongo() // connection to 127.0.0.1:27017
1.3.7 删除数据库
虽然数据库删除成功,但是通过db还是可以访问到
> db tab
> db.dropDatabase()
{ "ok" : 1 }
> db
tab
1.3.8 查询当前所使用的数据库
db.getName()
tab
1.4 collection 聚集集合操作
1.4.1 创建一个聚集集合
db.createCollection(name, options)
db.createCollection("collName", {size: 20, capped: true, max: 100});
参数说明:
- name: 要创建的集合名称
- options: 可选参数, 指定有关内存大小及索引的选项
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔(可选) | 如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。 |
autoIndexId | 布尔(可选) | 如为 true,自动在 _id 字段创建索引。默认为 false。 |
size | 数值(可选) | 为固定集合指定一个最大值(以字节计)。如果 capped 为 true,也需要指定该字段。 |
max | 数值(可选) | 指定固定集合中包含文档的最大数量。 |
- 创建了一个集合course,用于存储课程大纲
> db.createCollection("course")
{ "ok" : 1 }
> show dbs
admin 0.000GB
local 0.000GB
tab 0.000GB // 本次执行多了tab,因为不再是空的数据库了
1.4.2 得到指定名称的聚集集合
> db.getCollection('course')
tab.course
1.4.3 得到当前DB的所有的聚集集合
> db.createCollection("users")
{ "ok" : 1 }
> db.getCollectionNames()
[ "course", "users" ]
1.4.4 显示当前db所有集合的状态
db.printCollectionStats();
1.5 document文档操作
增删改查
1.5.1 插入文档
MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:
db.COLLECTION_NAME.insert(document)
db.collection.insertOne(document) // 向指定集合中插入一条文档数据
db.collection.insertMany(document) // 向指定集合中插入多条文档数据
> db.users.insertOne({
username: '大大',
password: '123456',
age: 18,
sex: '男'
{ "acknowledged" : true,
"insertedId" : ObjectId("5cda35212f11bdac31760139")
}
> db.users.insertMany([{
username: '钟钟',
password: '123',
age: 22,
sex: '女'
},{
username: '小小',
password: '456',
age: 20,
sex: '女'
}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5cda36372f11bdac3176013a"),
ObjectId("5cda36372f11bdac3176013b")
] }
插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。
1.5.2 查询数据
> db.users.find().pretty() // 使用 pretty() 方法以格式化的方式来显示所有文档
{
"_id" : ObjectId("5cda35212f11bdac31760139"),
username: '大大',
password: '123456',
age: 18,
sex: '男'
}
{
"_id" : ObjectId("5cda36372f11bdac3176013a"),
username: '钟钟',
password: '123',
age: 22,
sex: '女'
}
{
"_id" : ObjectId("5cda36372f11bdac3176013b"),
username: '小小',
password: '456',
age: 20,
sex: '女'
}
1.5.3 删除数据
> db.users.deleteOne({password: '456'})
{ "acknowledged" : true, "deletedCount" : 1 }
{
"_id" : ObjectId("5cda35212f11bdac31760139"),
username: '大大',
password: '123456',
age: 18,
sex: '男'
}
{
"_id" : ObjectId("5cda36372f11bdac3176013a"),
username: '钟钟',
password: '123',
age: 22,
sex: '女'
}
> db.users.deleteMany({})
{ "acknowledged" : true,"deletedCount" : 2 }
> db.users.find().pretty()
1.5.4 修改数据
db.col.updateOne({key: value}, {$set: {key: value}})
db.col.updateMany({key: value}, {$set: {key: value}})
db.col.updateOne({key: value}, { $inc: {key: num}}) 修改某一条数据的某一个字段key的自增num
1.6 查询数据
db.users.find({},{}).pretty() // 查询所有的数据,显示所有的字段
db.users.find({},{_id: 0}).pretty() // 不显示_id字段
db.users.find({},{_id: 0, username: 1}).pretty() // 不显示_id字段,只显示username字段’
db.users.find({},{_id: 0, username: 1, age: 1}).pretty() // 不显示_id字段,显示username字段’和age字段
db.users.find({
$or: [
{password: ‘123’},
{password: ‘456’}
]
}, {_id: 0}).pretty()
//满足password:‘123’,或password:'456’的显示
查询年龄在24岁以上的数据用 gt, 大于等于用gte
db.users.find({age: {$gt: 22} }, {_id:0}).pretty()
查询年龄在24岁以下的数据用 lt, 小于等于用lte
db.users.find({age: {$lt: 24} }, {_id:0}).pretty()
查询18-20之间的数据
db.users.find({age: { $gte: 18, $lte: 20}}, {_id:0}).pretty()
按照年龄排序 .sort({key:num}) num为1表示按照key值升序,为-1表示降序
db.users.find({}, {_id: 0}).sort({age: 1}).pretty()
查询数据并且计数 .count()
db.users.find({}, {_id: 0}).count()
db.users.find({age: { $gte: 18, $lte: 20}}, {_id:0}).count()
模糊查询 ---- 搜索框搜索产品
db.users.find({username:‘大’}, {_id:0}).pretty() // 精确查询,没有数据
db.users.find({username: /大/}, {_id:0}).pretty()
查询名字中含有大 或者 含有萌的 *
db.users.find({ $or: [{username: /大/}, {username: /小/}]}, {_id:0}).pretty()
2.nodejs结合Mongodb
2.1 安装mongoose
cnpm i mongoose -S
-S --save
-D --save-dev
2.2 连接数据库
新建一个db.js文件
const mongoose = require('mongoose');
const DB_URL = 'mongodb://127.0.0.1:27017/tab';
mongoose.connect(DB_URL, { useNewUrlParser: true });
mongoose.connection.on('connected', () => { console.log('数据库已经连接成功'); });
mongoose.connection.on('disconnected', () => { console.log('数据库连接失败'); });
mongoose.connection.on('error', () => { console.log('数据库连接异常'); });
首先确保数据库连接池是打开的,如果未打开,请参照1.2.1步骤,然后运行 node db.js 指令,发现打印出了 ‘数据库已经连接成功’ 字样
此时数据库连接已经搞定,接下来就是去处理后续的业务逻辑,按照模块化的开发思想,需要将db.js连接数据库的文件暴露出去 ----- 自定义模块
const mongoose = require('mongoose');
const DB_URL = 'mongodb://127.0.0.1:27017/sh1902';
mongoose.connect(DB_URL, { useNewUrlParser: true });
mongoose.connection.on('connected', () => { console.log('数据库已经连接成功'); });
mongoose.connection.on('disconnected', () => { console.log('数据库连接失败'); });
mongoose.connection.on('error', () => { console.log('数据库连接异常'); });
module.exports = mongoose;
2.3 设计用户数据表 — 暴露了数据模型,并且在数据库中创建了集合
mongoose.model(‘User’, UserSchema); 就会创建users集合
mongoose.model(‘Product’,ProductSchema); 就会创建products集合
mongoose.model(‘MyBanner’, BannerSchema); 就会创建mybanners集合
const mongoose = require('./db.js');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: { type: String },
password: { type: String },
age: { type: Number },
sex: { type: String },
}); // 执行时 会在数据库中创建users集合
module.exports = mongoose.model('User', UserSchema);
2.4 增删改查操作
2.4.1 查询数据的另一种写法
User.find({},{},(err,data) => {})
User.find({},{}).exec((err, data) => {}) // *********************
const User = require('./users');
// User.find({}, {_id: 0, __v: 0}, (err, data) => {
// if (err) throw err;
// console.log(data)
// })
// User.find({}, {_id: 0, __v: 0}).exec((err, data) => {
// if (err) throw err;
// console.log(data)
// })
User.find({}, {_id: 0, __v: 0}).sort({age: 1}).exec((err, data) => {
if (err) throw err;
console.log(data)
})
2.4.2 增
// 插入用户 const User = require('./Users');
const user = new User({
username: '刘杨',
password: 'aaa',
age: 22,
sex: '男',
})
user.save((err) => {
if (err) throw err;
console.log('用户插入成功') })
2.4.3 修改数据
User.updateOne({key, value}, {$set: {}}, err => {}) // $inc
新建update.js
const User = require('./users');
User.updateOne({username: '大'}, {$set: {age: 20}}, err => {
if (err) throw err;
console.log('修改成功')
})
User.updateMany({}, {$set: {password: '111'}}, err => {
if (err) throw err;
console.log('修改成功')
})
2.4.4 删除数据
User.deleteOne({key:value}, err => {})
新建delete.js
const User = require('./users');
// User.deleteOne({username: '大大'}, err => {
// if (err) throw err;
// console.log('删除成功')
// })
// style.display = 'flex' <==> style['display'] = 'flex'
User['deleteOne']({username: '大大'}, err => {
if (err) throw err;
console.log('删除成功') })
3. 封装数据库模块
3.1 创建如下的目录结构
sql
model
users.js
db.js
index.js
db.js就是之前写的,没有发生改变
users.js也是之前写的,唯一发生改变的就是引入db.js的路径
index.js 封装的数据的增删改查
module.exports = {
insert (insertData) {
insertData.save(err => {
if (err) throw err;
console.log('insert success');
})
},
delete: (col, type, deleteData) => {
col[type](deleteData, err => {
if (err) throw err;
console.log('delete success');
})
},
update: function (col, type, whereObj, updateObj) {
col[type](whereObj, updateObj, err => {
if (err) throw err;
console.log('update success');
})
},
find (col, whereObj, showObj) {
col.find(whereObj, showObj).exec((err, data) => {
if (err) throw err;
console.log(data);
})
},
sort (col, whereObj, showObj, sortObj) {
col.find(whereObj, showObj).sort(sortObj).exec((err, data) => {
if (err) throw err;
console.log(data);
})
}
}
3.2 验证封装的模块
3.2.1 插入
insertData.js
const sql = require('./sql/index'); // const sql = require('./sql');
const User = require('./sql/model/users');
const user = new User({
username: '小芳',
password: '458',
age: 16,
sex: '女',
})
sql.insert(user)
3.2.2 删除
deleteData.js
const sql = require('./sql');
const User = require('./sql/model/users');
sql.delete(User, 'deleteOne', { username: '小芳'})
3.2.4 查询数据
findData.js
const sql = require('./sql');
const User = require('./sql/model/users');
// sql.find(User, {}, {_id: 0, __v: 0})
sql.sort(User, {}, {_id: 0, __v: 0}, {age: 1})
思考:目前只是封装了模块,测试也是ok的,但是远远不够,还不能运用到项目中
思路:在封装模块出,如果得到了想要的结果,告诉调用他的人,如果有数据,则传递
方法: 回调函数/promise
3.3 回调函数解决异步数据问题
在每一个函数后边再新添加一个参数callback
insert (inserData, callback) {
insertData.save(err => {
if (err) throw err;
callback();
})
}
sql.insert(user, () => {console.log(''insert success)})
3.4 promise解决异步数据问题
insert (inserData) {
return new Promise((resolve, reject) => {
insertData.save(err => {
if (err) throw err;
resolve();
})
})
}
sql.insert(user).then(() => {console.log(''insert success)})
今天的学习就到这咯,请多指教