even

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

1、mongodb的索引

索引包含单键索引和复合键索引, 单键索引是针对一个字段进行排序,而复合键索引可以对多个字段进行排序, 复合键索引只支持前缀子查询

索引操作

db.COLLECTION_NAME.getIndexes()  --获取索引
db.COLLECTION_NAME.createIndex() --创建索引
db.COLLECTION_NAME.dropIndex()  --删除索引

索引类型

单键索引
多键索引
复合键索引

索引的特性: 唯一性, 稀疏性,生存时间

索引合理性分析: explain()

创建索引

db.goods.createIndex({name: 1, price: -1})   --表示创建多键索引

注意:1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可

检测索引

db.goods.explain().find({name: 'apple'})

注意:在检测结果中如果是COLLSCAN,那么就表示是通过遍历来获取结果的, 如果是IXSCAN则表示是通过索引来获取的效果会比COLLSCAN来的好,但是第三种情况最佳

创建唯一性索引

db.goods.createIndex({name: 1}, {unique: true})  --表示创建唯一性索引

parse选项:对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. 

expireAfterSeconds:指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。单位是秒

索引的其他操作

db.goods.getIndexes()  --查看所有的索引集合
db.goods.dropIndex("索引名")  --删除指定的索引
db.goods.dropIndexes()  --删除所有的索引

2、mongodb复制集

优点: 高可用性, 数据安全, 分流/分工

复制集的特点: 

  1. 主节点负责处理所有的写入请求
  2. 主节点(默认)和副节点都可以处理读取请求
  3. 副节点从主节点(或者符合条件的副节点)处复制数据
  1. 复制集中每个节点都会向其他节点发送心跳请求
  2. 每隔2秒发送一次, 超过10秒则请求超时(默认)
  3. 复制集中最多可以有50个节点

 创建复制集的数量是至少3个

具体查看网上文档

3、数据库安全

启用验证  --修改mongodb的配置文件

 

 在配置文件中开启权限验证

security:
  authorization: enabled

启用身份验证 --先关闭mongo  

net stop MongoDB  // 停止服务
net start MongoDB // 开启服务

创建一个超级用户

db.createUser({user: "admin", pwd: "123456", roles: [{role: "root", db: "admin"}]})

删除用户

db.dropUser("admin")  -- 表示删除指定的数据库用户

进行登录

mongo admin -u "admin" -p "123456"
--这里的root表示用户名, password表示密码

指定一个操作用户的操作步骤

> show dbs;
admin   0.000GB
config  0.000GB
even    0.000GB
local   0.000GB

use even
show users  -- 查看当前数据库的所有用户

db.createUser({user: "even", pwd: "123456", roles: [{role: "dbOwner", db: "even"}]})  --创建该数据库的用户,只能操作该数据库

--使用新账号登录
mongo even -u "even" -p "123456"

也可以按以下流程进行登录

mongo  --启动服务器
use admin  --进行admin表
db.auth("root", "password")  --进行身份验证

角色权限配置

Built-In Roles(内置角色):

  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

具体角色:

Read:允许用户读取指定数据库

readWrite:允许用户读写指定数据库

dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile

userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户

clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。

readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限

readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限

userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限

dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。

root:只在admin数据库中可用。超级账号,超级权限。

 创建新角色

db.createRole({ role: “testRole”, privileges: [{ resource: { db: “”, collection: “” }, actions: [“enableSharding” ] }], roles: [“readWriteAnyDatabase”] })

db.createUser( { user: “testuser”, pwd: “123456”, roles: [ { role: “testRole”, db: “admin” } ] } ) 

 4、使用mongoose操作数据库

安装数据库

yarn add mongoose
yarn add @types/mongoose --dev   // mongoose的类型声明库

数据库的基本操作

import { connect, Model, model, Schema, Document } from 'mongoose'

// 使用mongoose连接数据库,这里使用的是密码连接
connect('mongodb://even:123456@127.0.0.1:27017/even')

// 声明数据库的document
interface userDocument extends Document {
  name: string
  age: number
}

// 声明Schema
const userSchema: Schema<userDocument> = new Schema({
  name: {
    type: String,
    required: true
  },
  age: {
    type: Number,
    required: true
  }
})

//创建model, 注意第三个参数是数据库的真字表名
const userModel: Model<userDocument> = model('User', userSchema, 'user')

// 查询所有数据
userModel.find({}, { _id: 0, __v: 0 }, (err: any, doc: any) => {
  if (err) {
    console.error(err)
    return
  }
  console.log(doc)
})

 5、mongoose模块化以及预订义修饰符的使用

场景: 在models下新建三个文件,db.ts, user.ts, bag.ts

db.ts实现连接

import { connect } from 'mongoose'
export { Model, model, Schema, Document } from 'mongoose'

connect('mongodb://even:123456@127.0.0.1:27017/even', (err) => {
  if (err) {
    console.log(err)
    return
  }

  console.log('数据库连接成功')
})

user.ts

import { Model, model, Schema, Document } from './db'

export interface UserDocument extends Document {
  name: string
  age: number
}

const UserSchema: Schema<UserDocument> = new Schema({
  name: {
    type: String,
    unique: true,
    required: true
  },
  age: {
    type: Number,
    required: true,
    get(value) {
      //值得一提的是,getter不会修改数据库中返回的数据,而是在获得doc对象后,再访问其中的属性时候才会生效
      return value
    },
    set(value: any) {
      if (typeof value === 'string') return 0
      return value
    }
  }
})

export const UserModel: Model<UserDocument> = model('user', UserSchema, 'user')

注意: get定义后不会修改数据本身,而是在数据对象中添加了get的方法,只有在访问其中的属性的时候才会生效, 而set是在添加数据的时候,会对数据进行格式化, 如果需要设置普通索引,那么index: true, 如果需要设置唯一索引那么unique: true即可

bag.ts

import { Model, model, Schema, Document } from './db'

export interface BagDocument extends Document {
  name: string
  goods: string
  count: number
}

const BagSchema: Schema<BagDocument> = new Schema({
  name: {
    type: String,
    required: true
  },
  goods: {
    type: String,
    required: true
  },
  count: {
    type: Number,
    default: 0
  }
})

export const BagModel: Model<BagDocument> = model('Bag', BagSchema, 'bag')

对数据的调用和使用

import { UserModel, UserDocument } from '../../models/user'
import { BagModel, BagDocument } from '../../models/bag'

const getUser = (): Promise<Array<number>> => {
  return new Promise((resolve, reject) => {
    UserModel.find({}, (err, doc) => {
      if (err) return reject(err)
      let ages = doc.map((item) => item.age)
      resolve(ages)
    })
  })
}

const getBag = (): Promise<Array<BagDocument>> => {
  return new Promise((resolve, reject) => {
    BagModel.find({}, (err, doc) => {
      if (err) return reject(err)
      resolve(doc)
    })
  })
}

export const mongo = async () => {
  let user = await getUser()
  let bag = await getBag()
  return {
    user,
    bag
  }
}

 6、mongoose下自定义静态方法

import { Model, model, Schema, Document } from './db'

export interface UserDocument extends Document {
  name: string
  age: number
}

// 自定义方法接口
interface IUserModel extends Model<UserDocument> {
  findByName: (name: string, callBack: Function) => any
}

const UserSchema: Schema<UserDocument, IUserModel> = new Schema<UserDocument, IUserModel>({
  name: {
    type: String,
    unique: true,
    required: true
  },
  age: {
    type: Number,
    required: true
  }
})

// 自定义方法实体
UserSchema.static('findByName', function myStaticMethod(name: string, callBack) {
  this.find({ name }, (err: any, doc: any) => callBack(err, doc))
})

//暴露出去的方法,注意对model的类型声明
export const UserModel = model<UserDocument, IUserModel>('user', UserSchema, 'user')

 注意:自定义内部扩展方法,mongoose官网暂没有相关的ts版本,使用UserSchema.method(name, funciton)进行定义,但是这个方法使用的较少

7、mongoose下进行数据较验

 required : 表示这个数据必须传入

 max: 用于 Number 类型数据,最大值

 min: 用于 Number 类型数据,最小值

 enum:枚举类型,要求数据必须满足枚举值 enum: ['0', '1', '2']

 match:增加的数据必须符合 match(正则)的规则

 maxlength:最大值

 minlength:最小值

var UserSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  age: {
    type: Number, // 是否必须的校验器
    required: true, // 数字类型的最大值校验器
    max: 120, // 数字类型的最小值校验器
    min: 0
  },
  status: {
    type: String, // 设置字符串的可选值
    enum: ['0', '1', '2']
  },
  phone: {
    type: Number,
    match: /^\d{11}$/
  },
  desc: {
    type: String,
    maxlength: 20,
    minlength: 10
  }
})

自定义验证器

var UserSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  age: {
    type: Number, // 是否必须的校验器
    required: true, // 数字类型的最大值校验器
    max: 120, // 数字类型的最小值校验器
    min: 0
  },
  status: {
    type: String, // 设置字符串的可选值
    enum: ['0', '1', '2']
  },
  desc: {
    type: String, // 自定义的验证器,如果通过验证返回 true,没有通过则返回 false
    validate: function (desc) {
      return desc.length >= 10
    }
  }
})

 8、mongoose下聚合管道的使用

const check = () => {
  return new Promise((resolve, reject) => {
    UserModel.aggregate(
      [
        { $match: { name: { $eq: 'even' } } },
        { $project: { name: 1, _id: 0, age: 1 } },
        {
          $lookup: {
            from: 'bag',
            let: { n: '$name' },
            pipeline: [
              { $group: { _id: '$name', sum: { $sum: '$count' } } },
              { $match: { $expr: { $eq: ['$$n', '$_id'] } } }
            ],
            as: 'info'
          }
        }
      ],
      (err: any, doc: any) => {
        if (err) {
          return reject(err)
        }
        resolve(doc)
      }
    )
  })
}

export const mongo = async () => {
  const json = await check()
  return json
}

 注意:在使用objectid进行匹配的时候,使用官方的方法,mongoose.Types.objectId(id)

 

posted on 2021-08-19 12:44  even_blogs  阅读(74)  评论(0编辑  收藏  举报