express+mongoDB开发入门教程之mongoose使用讲解

发布时间:2024年01月03日

系列文章



前言

??????本文将讲述Mongoose的入门开发教程,以及通过一些示例演示对mongoDB数据库的增删改查操作。


一、Mongoose是什么?

??????Mongoose是一个强大的Node.js库,它提供了对MongoDB数据库的操作,有了Mongoose实际开发中对MongoDB增删改查将变得很容易。

二、Mongoose安装

npm install mongoose -S

目前mongoose最新版本是v8.0,要求安装node v16以上版本,不同的mongoose版本一些api使用方式是有区别的,8.0操作上把旧版本的回调函数改成promise( aysnc/await)形式


三、Mongoose在express项目中使用

在项目根目录新建model文件夹放置Mongoose相关文件,model目录下新建db.js文件

在这里插入图片描述

步骤一、连接mongoDB数据库

假设连接到名为system数据库

db.js文件写入

const mongoose = require("mongoose");
//数据库连接地址+数据库名称(system)
const DBURL='mongodb://127.0.0.1:27017/system'
//连接数据库
 mongoose.connect(DBURL).then(res=>{
    console.log('连接成功')
 }).catch(e=>{
    console.log('连接失败')
 })
 
module.exports = mongoose;

通过API mongoose.connect 连接数据库,其中system为想要连接的数据库名称,返回值Promise,通过then/catch或async/await监听连接失败或成功。当然也可以通过监听连接事件connected和error来判断,需要注意的是数据库名即使不存在也能连接成功,在mongoDB中不存在的库或者集合在进行数据添加操作的时候会自动生成,最后导出mongoose供后续创建模型使用。

连接成功与否也可以通过监听连接事件:

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

mongoose.connection.on('error',err=>{
    console.log('数据库连接失败')
})

其他连接事件还有:

  • connecting:初始连接时发出
  • open:在所有该连接的模型上执行 ‘connected’ 和 onOpen 后发出
  • disconnecting:断开连接发出
  • close:成功关闭连接
  • reconnected:重新连接成功发出

步骤二、建立模型

模型可以理解成每个文档字段配置,建立模型就是对字段属性进行设置,生成一个模型对象,后续增删改查操作将基于该模型对象进行方法调用

假设现在有个管理后台要存储用户信息,信息包括姓名、年龄、性别3个字段,集合名称为user
在model目录下新建user.js文件

在这里插入图片描述
写入:

const db = require("./db");

//定义结构
let userSchema = db.Schema(
  {
    name: {
      type:String,
      required:true
    },
    age: Number,
    sex: {
      type:String,
      default:'未知'
    },
  },
  { versionKey: false }//隐藏_v字段
);

//创建模型
let userModel = db.model("user", userSchema, "user");

module.exports = userModel;

在这里插入图片描述

先通过mongoose.Schema定义文档字段配置,再调用mongoose.model生成模型对象,最后导出模型对象供增删改查操作使用

mongoose.Schema 类似vue props可以设置字段类型、是否必填、默认值等

type:有效类型有如下:

  • 字符串 String
  • 数字 Number
  • 日期 Date
  • 缓冲 Buffer
  • 布尔值 Boolean
  • 混合 Schema.Types.Mixed
  • ObjectId Schema.Types.ObjectId
  • 数组 []
  • 十进制 128 Schema.Types.Decimal128
  • 映射 Map
  • 结构 subSchema
  • UUID Schema.Types.UUID
  • BigInt BigInt

required:是否必填true/false
default:默认值

?????需要注意的是我们发现上面代码db.model(“user”, userSchema, “user”)生成模型时候传入3个参数其中第一个和第三个参数都是user。user为要操作的集合(表)名称,如果不设置第三参数类似db.model(“user”, userSchema)最终操作的是users集合,因为mongoose会默认在参数后面加s,实际变成users,好在提供第三个参数,我们可以通过第三个参数设置真实集合名称。
?????给集合添加一个新文档默认会生成_id和_v字段,想要隐藏_v字段可以设置 versionKey: false

除了以上几个属性还有更多配置属性可以查看官网SchemaType

步骤三、增删改查操作

增删改查操作都是基于步骤二导出的模型进行函数调用,常用的命令可以总结如下表所示

API说明
Model.create()新增一条数据
Model.deleteOne()删除一条数据
Model.deleteMany()删除多条数据
Model.updateOne()修改一条数据
Model.updateMany()修改多条数据
Model.find()查找满足条件所有数据
Model.findOne()查找满足条件第一条数据
Model.findById()通过id查找一条数据
Model.findOneAndUpdate()查找一条数据修改并返回

下面所有示例将在routers/users.js文件内进行编写,该路由前缀为users,并在app.js注册,模型userModel由上面步骤二所创建

1、 新增数据

方法一:Model.create()

//导入模型
var userModel = require("../model/user");

//新增接口
router.post("/create", async (req, res) => {
  try {
    await userModel.create({ name:'李磊', age:20, sex:'男' });
    res.send({
      code: 200,
      msg: "success",
    });
  } catch (e) {
    res.send({
      code: 500,
      msg: e.message || "fail",
    });
  }
});

方法二:Document.save()

//导入模型
const userModel = require("../model/user");

//新增接口
router.post("/create", async (req, res) => {
  try {
    let doc=new userModel({ name:'李磊', age:20, sex:'男' })
    await doc.save()
    res.send({
      code: 200,
      msg: "success",
    });
  } catch (e) {
    res.send({
      code: 500,
      msg: e.message || "fail",
    });
  }
});

请求接口:

在这里插入图片描述

数据库数据:

在这里插入图片描述

动态获取新增参数示例:

//导入模型
const userModel = require("../model/user");
//新增接口
router.post("/create", async (req, res) => {
 //获取请求参数,请求数据为json格式
  let { name, age, sex } = req.body;  
  try {
    await userModel.create({ name, age, sex });
    res.send({
      code: 200,
      msg: "success",
    });
  } catch (e) {
    res.send({
      code: 500,
      msg: e.message || "fail",
    });
  }
});

执行新增请求:

在这里插入图片描述

数据库数据

在这里插入图片描述
ps:上面请求新增时候我们并没有传sex值,由于在创建模型时候sex设置了默认值为"未知"所以当请求没有传值默认保存为"未知",并且数据库默认会为每条数据创建一个_id字段作为唯一标识

2、更新数据

更新单条数据:

例如:修改李磊年龄为22岁

 userModel.updateOne({ name: "李磊" }, { age: 22 });

更新多条数据

例如:修改所有年龄为22岁的用户为男性

 userModel.updateMany({ age: 22 }, { sex:"男性" });

动态传参更新

通过传入id,更新其他字段值

//导入模型
const userModel = require("../model/user");
//更新
router.post("/update", async (req, res) => {
  let {id,name,age,sex}=req.body
  if(!id){
    res.send({
      code: 500,
      msg: "id不能为空",
    });
    return;
  }

  try {
   await userModel.updateOne({ _id: id }, {name,age,sex });
    res.send({
      code: 200,
      msg: "success",
    });
  } catch (e) {
    res.send({
      code: 500,
      msg: e.message || "fail",
    });
  }
});

接口请求测试
修改李磊年龄为100,性别为女

在这里插入图片描述

数据库数据:

在这里插入图片描述

ps:Model.updateOne/Many(condition,newVal),第一个参数为查询条件,为对象可以设置多个属性,第二个为更新的值也是个对象可以设置多个属性

3、删除数据

删除单条
例如:删除李磊用户

  userModel.deleteOne({ name: "李磊" });

删除多条

例如:删除所有男性用户

  userModel.deleteMany({ sex: "男性" });

4、查找数据

查找单条数据:

 let data=await userModel.findOne({ sex: "男性" });//查找第一条性别为男的数据
 let data2=await userModel.findById("6594c18f112053f96104b7a1");//通过id查找数据

查找所有满足条件数据

//查找年龄为10岁,性别为男性的所有数据
let data=await userModel.find({age:10, sex: "男性" });
筛选条件

增加筛选条件方法比较多,这里就挑一些比较常用讲解

1、运算符(><=!==)
  //查找年龄大于10岁,小于30岁数据
 let data=await userModel.find({age:{$gt:10,$lt:30}});

也可以用链接语法构建查询

 let data=await userModel.find().where('age').gt(10).lt(33).exec();

上面两句是等价的。

所有运算符如下:

运算符说明
$gt大于>
$gte大于等于>=
$lt小于<
$lt小于等于<=
$ne不等于!=
2、枚举值 $in
//查找性别为男性或男或未知的所有数据
  let data=await userModel.find({ sex: { $in: ['男性','男','未知'] }});

链接语法构建查询

let data=await userModel.find().where('sex').in(['男性','男', '未知']);
3、逻辑运算$or/and
//查找年龄为10岁或者20岁数据
  let data=await userModel.find({$or: [{age:10}, {age:20}]});
//查找年龄为10岁且为男性数据
  let data=await userModel.find({ $and: [{age:10}, {sex:"男性"}]});
4、正则匹配
//查找名字带小的所有数据
  let data=await userModel.find({name://});
5、排序sort
//查找所有数据按年龄正序排序返回
  let data=await userModel.find().sort({ age: 1 });
//查找所有数据按年龄倒序排序返回
  let data=await userModel.find().sort({ age: -1 });

ps:1正序,-1倒序

6、限制个数limit
//返回10个数据
  let data=await userModel.find().limit(10);
7、跳过个数skip
//跳过前100个返回第101-110位置数据
  let data=await userModel.find().skip(100).limit(10);
8、设置数据返回字段select
//返回数据只有name、age字段
  let data=await userModel.find().select('name age');
9、查询总数量count
//返回数据总个数
  let data=await userModel.find().count();//2
demo演示:

下面结合开发实际场景写一个例子来演示下筛选条件使用

在这里插入图片描述

假设我们要实现上面一个列表页,其中姓名支持模糊搜索,带分页功能

var express = require("express");
var router = express.Router();
//导入模型
const userModel = require("../model/user");

//分页查询接口
router.post("/findByPage", async (req, res) => {
  let { name, age, sex, page, size } = req.body;
  //查询参数过滤掉值为undefined或null或空值属性
  let params = Object.entries({ name, age, sex }).reduce((prev, cur) => {
    let [key, value] = cur;
    if (value!==undefined&&value!==null&&value!=='') {
      if (key === "name") {
        //名字模糊搜索正则处理
        prev[key] = new RegExp(value);
      } else {
        prev[key] = value;
      }
    }
    return prev;
  }, {});


  try {
    let query = userModel.find(params);
    if (page && size) {
      //获取分页数据
      query.skip((page - 1) * size).limit(size);
    }
    let data = await query.exec();//分页数据
    let total= await userModel.find(params).count();//总条数
    res.send({
      code: 200,
      data,
      total,
      msg: "success",
    });
  } catch (e) {
    res.send({
      code: 500,
      msg: e.message || "fail",
    });
  }
});

现有数据库数据:

在这里插入图片描述

测试请求数据

1.分页在这里插入图片描述
2.模糊搜索
在这里插入图片描述
3.其他
在这里插入图片描述

ps:查询条件某字段值如果是undefined或者空值''或者null条件参数JSON对象要过滤掉该属性否者查出来数据为空

至此最基本入门技能——增删改查操作已经介绍完,更多细节、技巧和api请查阅官方文档 https://mongoose.nodejs.cn/docs/queries.html

文章来源:https://blog.csdn.net/sd1sd2/article/details/135342464
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。