MongoDB
常用数据库
关系型数据库
- mysql
- oracle
- PostgreSQL
- 传统 sql类型语言
- 支持json
- 适合分布式系统
nosql数据库(key/value数据库)
- mongodb
- 分布式系统有良好的兼容性
- 对机器的要求高一点,但是能承受的并发量,和读写单表的数据大小要比mysql好很多
- 在老一点版本mysql 5.7之前,单表数据1000万的时候,进行插入和加索引查询比较慢,而mongoDB到达1亿左右的数据都不会有明显的下降
- redis
- memocache
mongoDB 使用
docker run -p 27017:27017 -v $PWD/db:/data/db -d mongo:3.6.15 docker ps -a 查看 mongo id编号 # 进入 容器内部 docker exec -it id编号 bash # 开启 mongodb mongo
# 使用方式 # 使用我们的数据库 不存在则创建 use what_i_love
# 查看表 show collections;
# 插入数据 同时创建表 db.users.insert({name:"hjx",age:100})
# 查询数据 db.users.find()
# 查询数据 查看数据方式美化 db.users.find().pretty()
# 更改数据 db.users.update({name:"hjx"},{name:"hjx",age:20})
# 删除数据 db.users.remove({})
# 查看帮助文档 db.users.help()
# 创建索引 db.users.createIndex({name:1})
# 获取索引 db.users.getIndexes({name:1})
|
ObjectId 问题
# 插入单条数据,他会把插入后的 id返回给你 db.users.insertOne({name:'hjx',age:29}) # 返回内容如下 { "acknowledged" : true, "insertedId" : ObjectId("5e8e8c929f5bb82134fad5db") }
|
特别是你想生成一个自增长的主键,在分布式你会遇到问题
如何保证唯一性,如 mysql 的主键状态同步问题
- 一个表我分了表,数据会被同时存到两张不同的表里去,或者10多台不同的服务器上去
- 你就不能通过某一台服务器某一个数据库让它 +1,你必须问其他数据库 现在加到几了
mongodb的处理
- 首先有这个自增长的数字
- 其次时间戳
- 加上 机器编码
- 最后每个 mongo开启会有一个 进程号
ObjectId = 自增长id + 时间戳 + 机器编码 + mongoDB的进程号
有效避免了 mysql需要 全局维护一个自增长的变量来存储当前表里状态的情况
- 你始终要有一个地方 去存现在 id到底是几
- 如果这个业务中心这个服务挂掉了,你在其他地方想要恢复它是一个困难的问题
- 结论:最好不要有这个中心化的东西管理系统 处理这个 主键id
如果对数据有强烈要求(准确性)
- 电商/订单等问题 不要用mongoDB,而是mysql
mongoDB 添加字段问题
- 可方便的添加新的字段,不用像 mysql 那样设计的时候 定义扩展字段 (name,age,city ,extra1 , extra2, extra3)
db.users.insert({name:"hjx",age:100})
db.users.insert({name:"aaa",age:33,city:"tj"}) db.users.insert({name:"aaa",age:22,city:"bj"})
# 查询的时候 > db.users.find() { "_id" : ObjectId("5e8e8c929f5bb82134fad5db"), "name" : "hjx", "age" : 29 } { "_id" : ObjectId("5e8e97129f5bb82134fad5dc"), "name" : "aaa", "age" : 33, "city" : "tj" } { "_id" : ObjectId("5e8e97169f5bb82134fad5dd"), "name" : "aaa", "age" : 22, "city" : "bj" }
|
find条件筛选
# 查找 age = 30的 db.users.find({age:30})
# 操作符 大于12的 db.users.find({age: {$gt:12}})
# 操作符 大于等于12的 db.users.find({age: {$gte:12}})
# 操作符 小于等于12的 db.users.find({age: {$lte:12}})
# 大于等于12 小于等于30 db.users.find({age: {$lte:30 , $gte:12}})
# 是否存在 city db.users.find({city: {$exists:true}})
|
只要某些字段
# 默认会返回id 如果你不设置的话 # 查询所有数据 返回 id,age db.users.find({},{age:true}) db.users.find({},{age:1})
# 除了age其他字段都查出来 db.users.find({},{age:0})
|
update 的大惊喜
# 把你 name=hjx 的数据 改的只有 id 和 age db.users.update({name:'hjx'},{age:57})
# 务必用 $set 更新某一个字段的时候 db.users.update({name:'hjx'},{$set:{age:57}})
|
$unset
滞空值
# 去除 age字段 db.users.update({name:'hjx'},{$unset:{age:true}})
|
findOneAndUpdate
更新并返回 db.users.findOneAndUpdate({name:'hjx'},{$set:{age:11}},{returnNewDockment:true})
|
查询不到就新增
db.users.findOneAndUpdate({name:'hjx'},{$set:{age:11}},{upsert:true})
|
deleteOne
# 删除 name= aa city不存在的 db.users.deleteOne({name:'aa',city:{$exists:false}})
|
字段重命名
db.test.update({}, {$rename : {"abc" : "def"}}, false, true)
|
聚合操作
db.users.aggregate([ { $match:{ age:{ $exists:true }, name:{ $exists:true } } }, { $group:{ _id:"$name", avgName:{ $avg:'$age' } } } ])
|
索引问题
# name 根据升序排列 db.users.createIndex({name:1})
# 删除索引 db.users.dropIndex({name:1})
# 添加name唯一索引 db.users.createIndex({name:1},{unique:1})
# 获取索引 db.users.getIndexes()
|
各种操作参考
MongoDB
MongoDB作为最流行的NoSQL数据库之一,运用灰常广泛,其友好的JSON支持和灵活的表单结构,使其在使用Node.js开发的诸多Web应用中非常受欢迎
在高性能分布式存储领域,MongoDB也有一席之地,然而MongoDB对事务的不友好和过于灵活的特性也带来了一些问题
mongoose
mongoose是MongoDB的Node.js框架,在处理MongoDB表管理、验证方面有方便之处
hello world
const mongoose = require('mongoose');
mongoose.Promise = Promise;
const uri = `mongodb://localhost:27017/what_i_love`; mongoose.connect(uri, { useMongoClient: true }); const db = mongoose.connection;
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;
const UserSchema = new Schema({ name: { type: String, required: true, unique: true, index: 1 }, age: { type: Number, max: 188, min: 0 }, });
const UserModel = mongoose.model('user', UserSchema);
(async (params) => {
const filter = {}; if (params.name) filter.name = params.name;
const flow = UserModel.find(filter);
if(params.projection) flow.select(params.projection);
if(params.sort) flow.sort(params.sort);
const users = await flow.exec();
return users;
})({ name:"xiaoli", projection: {age:1}, // sort:{age:-1}, sort:'-age' }) .then(r => { console.log(r); }) .catch(e => { console.log(e); });
db.on('open', () => { console.log('db connected!'); });
db.on('error', (e) => { console.log(e); });
|
Schema属性和验证
{ name:{ type: String, required: true }, //存储之前会验证 age:{ type:Number, min:1, max:[12, 'Growned are not welcome!'], }, address:[new Schema({ city:String, province:String, })] }
|
查询(流)
const query = Model.find({name:{$regex:"a"}}); query.where('age').lte(2); if(params.limit) query.limit(params.limit); query.sort('-age');
const result = await query.then();
|
使用Schema.statics和Schema.method可以定义用于查询的方法