要一直走下去

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

1、MongoDB的介绍

MongoDB是一个文档数据库,存放的是BSON,使用非常方便:直接能把Json存进去,并且从数据库中查询出来就是JSON

数据库软件安装地址:https://www.mongodb.com/download-center/community
可视化软件安装地址:https://www.mongodb.com/download-center/compass
 

 

 

 

 

2、MongoDB可视化工具

数据库列表:

 

 

 集合列表,这里相当于mysql的表

 

 

 集合里的文档,相当于mysql的一条数据

 

 

 

3、MongoDB创建集合、文档

安装mongoose包:`npm install mongoose`
mongoose官方文档地址:https://mongoosejs.com/docs/connections.html
 
连接数据库,创建集合、文档
const mongoose = require('mongoose')
const schema = mongoose.Schema  //Schema用于定义collection的结构

//连接数据库,但是数据库test不存在,会自动创建,但要写内容才会创建
mongoose.connect('mongodb://localhost/test', {
    useNewUrlParser: true,  //不加这个有警告提示
    useUnifiedTopology: true //不加这个有警告提示
}).then(() => {
    console.log('连接数据库成功')
}).catch(err => {
    console.log(err, '连接数据库失败')
})

//创建集合结构
const userSchema = new schema({
    name: String,
    city: String,
    sex: Number
})

//创建集合,集合名称为users,自动给你加复数
const Model = mongoose.model('user', userSchema)

////创建文档并把文档插入数据库中:方式一
const doc = new Model({
    name: 'eric',
    city: '深圳',
    sex: 2
})
doc.save()


//创建文档并把文档插入数据库中:方式二(推荐)
Model.create({
    name: '嘻嘻',
    city: '广州',
    sex: 1
}, (err, doc) => {
    if (err) throw err
    console.log(doc)
})

 

4、MongoDB字段验证

  • required 验证字段是否为必须输入,值为boolean
  • minlength,maxlength 验证字符的值的最小长度和最大长度
  • trim 去除字符串守尾空格,值为boolean
  • min、max 验证最小最大数字
  • default 默认值
  • enum 规定输入的值
  • validate 自定义条件验证,通过validator函数处理输入值,message为自定义错误信息
  • 通过catch获取errors对象,遍历对象从中获取对应字段自定义报错信息

 

const mongoose = require('mongoose')
const schema = mongoose.Schema

mongoose.set('useFindAndModify', false)

//连接数据库
mongoose.connect('mongodb://localhost/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then(() => {
    console.log('连接数据库成功')
}).catch(err => {
    console.log(err, '连接数据库失败')
})

//创建集合结构
const userSchema = new schema({
    name: {
        type: String,
        required: [true, '该字段为必选字段'],
        minlength: [2, '输入值长度小于最小长度'],
        maxlength: [6, '输入值长度大于最大长度'],
        trim: true
    },
    age: {
        type: Number,
        min: 18,
        max: 30
    },
    createTime: {
        type: Date,
        default: Date.now
    },
    hobbies: {
        type: String,
        enum: {
            values: ['唱', '跳', 'Rap'],
            message: '该值不在设定的值当中'
        }
    },
    score: {
        type: Number,
        validate: {   //自定义验证规则
            validator: v => {
                //返回布尔值
                return v && v > 0 && v < 100
            },
            message: '不是有效的分数'
        }
    }
})

//创建集合
const Model = mongoose.model('user', userSchema)

Model.create({hobbies: '篮球', score: -1})
    .then(res => console.log(res))
    .catch(error => { //如果有多个报错信息,需要循环处理
        const errs = error.errors
        for (let [field, err] in Object.entries(errs)) {
            console.log(field, err.message)
        }
    })

5、MongoDB导入文件数据

将mongoimport命令加到环境变量:

 

待导入文件的格式:

 

 导入命令:

6、MongoDB查询文档

const mongoose = require('mongoose')
const schema = mongoose.Schema

//连接数据库
mongoose.connect('mongodb://localhost/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then(() => {
    console.log('连接数据库成功')
}).catch(err => {
    console.log(err, '连接数据库失败')
})

//创建集合结构
const userSchema = new schema({
    name: String,
    city: String,
    sex: Number,
    age: Number
})

//创建集合
const Model = mongoose.model('user', userSchema)

//查询多条:查询所有文档,res为数组
Model.find().then(res => {
    console.log(res)
})
//查询多条:查询name='6'的文档,res为数组
Model.find({name: '6'}).then(res => {
    console.log(res)
})
//查询多条:查询name='6'&& city='上海'的文档,res为数组
Model.find({name: '6', city: '上海'}).then(res => {
    console.log(res)
})

//查询单条:查询name='2'的文档,返回第一条,res为对象
Model.findOne({name: '2'}).then(res => {
    console.log(res)
})

//区间查询: 18<=age<=38
Model.find({age: {$gte: 18, $lte: 38}}).then(res => {
    console.log(res)
})
//模糊查询: 正则匹配
Model.find({city: /上/}).then(res => {
    console.log(res)
})
//限制返回字段:只返回name和city字段,以及_id字段
Model.find().select('name city').then(res => {
    console.log(res)
})
//限制返回字段:只返回name和city字段
Model.find().select('name city -_id').then(res => {
    console.log(res)
})
//限制返回字段:除了name其他都返回
Model.find().select('-name').then(res => {
    console.log(res)
})
//字段排序:加减号是降序,不加是升序
Model.find().sort('-age').then(res => {
    console.log(res)
})
//跳过以及限制:查全部数据,跳过前两条,只显示第3,4,5条
Model.find().skip(2).limit(3).then(res => {
    console.log(res)
})

7、MongoDB更新文档

const mongoose = require('mongoose')
const schema = mongoose.Schema

mongoose.set('useFindAndModify', false)  //不写这个会有警告信息

//连接数据库
mongoose.connect('mongodb://localhost/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then(() => {
    console.log('连接数据库成功')
}).catch(err => {
    console.log(err, '连接数据库失败')
})

//创建集合结构
const userSchema = new schema({
    name: String,
    city: String,
    sex: Number,
    age: Number
})

//创建集合
const Model = mongoose.model('user', userSchema)

//更新单个文档:
// 找到⼀个⽂档并更新,如果查询多个⽂档,则更新第⼀个匹配⽂档 返回值为更新后的⽂档
Model.findOneAndUpdate({name: '2'}, {city: '深圳'}).then(res => {
    console.log(res)
})
//更新单个文档:
//作用跟上面一样,更新指定条件⽂档,如果查询多个⽂档,则更新第⼀个匹配⽂档,
// 区别是返回值不同 {n:1,nModified:1,ok:1}
Model.updateOne({name: '2'}, {city: '上海'}).then(res => {
    console.log(res)
})
//更新多个文档:如果条件为空,则更新全部文档
Model.updateMany({}, {city: "深圳"}).then(res => {
    console.log(res)
})
//更新多个文档:更新所有name='2'的所有文档
Model.updateMany({name: '2'}, {city: "深圳"}).then(res => {
    console.log(res)
})

 

8、MongoDB删除文档

const mongoose = require('mongoose')
const schema = mongoose.Schema

mongoose.set('useFindAndModify', false)

//连接数据库
mongoose.connect('mongodb://localhost/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then(() => {
    console.log('连接数据库成功')
}).catch(err => {
    console.log(err, '连接数据库失败')
})

//创建集合结构
const userSchema = new schema({
    name: String,
    city: String,
    sex: Number,
    age: Number
})

//创建集合
const Model = mongoose.model('user', userSchema)

//删除单个文档:
//找到⼀个⽂档并删除,如果查询多个⽂档,则删除第⼀个匹配⽂档 返回值为该⽂档
Model.findOneAndDelete({name: 'xx'}).then(res => {
    console.log(res)
})
//删除单个文档:
//跟上面一样,只是返回值不一样 {n:1,ok:1,deleteCount:1}
Model.deleteOne({name: '2'}).then(res => {
    console.log(res)
})
//删除多个⽂档:如果条件为空,就删除全部文档
Model.deleteMany().then(res => {
    console.log(res)
})

 

9、示例

数据结构:

 

 

 

// 插入一条数据
function addPoints(cardId: string, statusId: string) {
    return models.cardStamp.updateOne({_id: cardId},
        {$push: {'stampHistories': {statusId: statusId, dates: points}}})
}
//更新cardId=?且statusId=?的dates数据
function updatePoints(cardId: string, statusId: string) {
    return models.cardStamp.updateOne(
        {
            _id: cardId,
            stampHistories: {
                $elemMatch: {
                    statusId: statusId
                }
            }
        },
        {$set: {'stampHistories.$.dates': points}})
}
//更新第一条数据
function updatePointsFirst(cardId: string) {
    return models.cardStamp.updateOne(
        {
            _id: cardId,
            stampHistories: {
                $elemMatch: {
                    index: 0
                }
            }
        },
        {$set: {'stampHistories.$.dates': points}})
}
Code

 

 

 

export default {
    local: "mongodb://localhost/test",
    st: "mongodb://kanban4st:Kanban%254st@kbmongo4st-0:27017,kbmongo4st-1:27017,kbmongo4st-2:27017/kanban?replicaSet=kbmongo4st&maxpoolsize=300&maxidletimems=180000&connecttimeoutms=10000&sockettimeoutms=60000&readpreference=secondaryPreferred",
    uat: "mongodb://kanban4uat:Kb#uat%251P#f@kanban4uat-0:27017,kanban4uat-1:27017,kanban4uat-2:27017/kanban?replicaSet=kanban4uat&maxpoolsize=300&maxidletimems=180000&connecttimeoutms=10000&sockettimeoutms=60000&readpreference=secondaryPreferred"
}
conf.ts

 

import mongoose from "mongoose";

mongoose.connection.once('open', () => {
    console.log('连接数据库成功')
})

mongoose.connection.once('close', () => {
    console.log('连接断开')
})

export default {
    cardStamp: mongoose.model('cardStamp', new mongoose.Schema({
                _id: String,
                troopId: String,
                kanbanType: String,
                archived: Boolean,
                stampHistories: Array({
                    _id: false,         // 建表不带_id字段
                    statusId: String,
                    dates: Array(Date),
                    projectKey: String
                })
            },
            {versionKey: false}  // 建表不带__v版本字段
        ), 'cardStamp'     // 表名不加s   第三个参数可以重命名这个集合
    )
}
model.ts

 

/// <reference path="./types.d.ts" />
import mongoose from "mongoose";

const axios = require("axios")
import model from "./model"

/** * 获取最近几天的日期 *
 * @param n
 * 往前推的天数 * getLatestDays(7) = [
 * '2022-11-17T16:00:00.000+0000',
 * '2022-11-16T16:00:00.000+0000',
 * '2022-11-15T16:00:00.000+0000',
 * '2022-11-14T16:00:00.000+0000',
 * '2022-11-13T16:00:00.000+0000',
 * '2022-11-12T16:00:00.000+0000',
 * '2022-11-11T16:00:00.000+0000']
 * */
function getLatestDays(n: number) {
    const currDate = new Date()
    return Array.from({length: n}, (v, k) => {
        const preDate = new Date(currDate.getTime() - (k + 1) * 24 * 60 * 60 * 1000)
        return `${preDate.getFullYear()}-${(preDate.getMonth() + 1).toString().padStart(2, '0')}-${preDate.getDate().toString().padStart(2, '0')}T16:00:00.000+0000`
    });
}

/** * 连接 Mongodb * @param uri */
async function connectMongodb(uri: string) {
    return await mongoose.connect(uri)
}

/** * 断开连接 Mongodb */
function disconnectMongodb() {
    mongoose.connection.close()
}

/**  根据cardId 获取 statusId ,用法:getCardStatusId('FEATURE002-747')
 *   @param cardId
 */
async function getCardPoint(cardId: string): Promise<CardStampType> {
    const res = await axios.get(`http://cmbkb-service-kanban-st.paasst.cmbchina.cn/tracking/cards/${cardId}`)
    const result: CardStampType = {
        _id: res.data.id,
        troopId: res.data.troop.id,
        kanbanType: res.data.troopKanbanType,
        archived: false,
        stampHistories: [
            {
                statusId: res.data.cardStatus.id,
                dates: getLatestDays(20),
            }
        ]
    }
    if (res.data.sprintId) {
        result.stampHistories[0].sprintId = res.data.sprintId
    }
    if (res.data.vpProject.id.indexOf("@default") == -1) {
        // 不是默认泳道
        result.stampHistories[0].projectKey = res.data.vpProject.id
    }
    return result
}

async function handleCardPoint(cardId: string) {
    const cardDetail = await getCardPoint(cardId)
    return new Promise((resolve, reject) => {
        model.cardStamp.deleteOne({_id: cardId}).then(res => {
            model.cardStamp.create(cardDetail, (err, doc) => {
                if (err) {
                    resolve(`${cardId}:失败`)
                }
                resolve(`${cardId}:ok`)
            })
        })
    })
}

export default {connectMongodb, disconnectMongodb, handleCardPoint, getLatestDays}
service.ts

 

interface StampHistory {
    statusId: string,
    dates: Array<string>,
    projectKey?: string,
    sprintId?: string
}

interface CardStampType {
    _id: string,
    troopId: string,
    kanbanType: string,
    archived: boolean,
    stampHistories: Array<StampHistory>
}
types.d.ts

 

import service from "./service/service"

import uri from "./service/conf"

const jobs = [
    service.handleCardPoint('Z990083-576')
]

service.connectMongodb(uri.st).then(() => {
    Promise.all(jobs).then(res => {
        console.log(res)
        service.disconnectMongodb()
    })
})
main.ts

 

posted on 2022-07-17 10:56  要一直走下去  阅读(852)  评论(0)    收藏  举报