Egg typescript 使用 egg-mongoose 教程

前言

本教程将引导你在 Egg.js 框架中使用 typescript,安装 egg-mongoose 插件连接和操作 MongoDB 数据库,涵盖安装、配置、模型定义、基本 CRUD 操作以及高级功能如聚合查询和关联查询。

https://www.eggjs.org/zh-CN/tutorials/typescript

本示例代码:https://gitee.com/OnlyDawn1122/egg-mongoose-demo

1. 前置条件

  • Node.js:确保已安装 Node.js(建议版本 14.x 或更高)。
  • MongoDB:本地或云端已安装并运行 MongoDB 数据库。你可以使用 MongoDB Atlas 或本地安装 MongoDB。
  • Egg.js 项目:已初始化一个 Egg.js 项目。如果没有,可通过以下命令创建:
    mkdir egg-mongoose-demo && cd egg-mongoose-demo
    npm init egg --type=ts
    npm i

image

1.1 本地 Docker 安装 mongodb

docker pull mongo:latest

imageimage
mongoDB 服务已启动:image

image


2. 安装 egg-mongoose

2.1 安装依赖

在项目根目录下运行以下命令安装 egg-mongoose 插件:

npm i egg-mongoose --save

2.2 启用插件

{app_root}/config/plugin.ts 中启用 egg-mongoose 插件:

// config/plugin.ts

module.exports = {
  mongoose: {
    enable: true,
    package: 'egg-mongoose',
  },
};

3. 配置 MongoDB 连接

{app_root}/config/config.default.ts 中配置 MongoDB 连接信息。支持单数据库和多数据库配置。

3.1 单数据库配置

// config/config.default.ts

module.exports = appInfo => {
  const config = exports = {};

  // 配置 mongoose
  config.mongoose = {
    client: {
      url: 'mongodb://127.0.0.1:27017/egg_mongoose_demo', // 替换为你的 MongoDB 地址
      options: {
        useNewUrlParser: true,
        useUnifiedTopology: true,
      },
    },
  };

  return {
    ...config,
  };
};

3.2 多数据库配置

如果需要连接多个 MongoDB 数据库,可以这样配置:

// config/config.default.ts

module.exports = appInfo => {
  const config = exports = {};

  // 配置 mongoose
  config.mongoose = {
    clients: {
      db1: {
        url: 'mongodb://127.0.0.1:27017/db1',
        options: {
          useNewUrlParser: true,
          useUnifiedTopology: true,
        },
      },
      db2: {
        url: 'mongodb://127.0.0.1:27017/db2',
        options: {
          useNewUrlParser: true,
          useUnifiedTopology: true,
        },
      },
    },
  };

  return {
    ...config,
  };
};

4. 定义模型(Model)

在 Egg.js 中,模型通常放在 app/model 目录下,用于定义 MongoDB 集合的 Schema 和 Model。

4.1 创建 User 模型

创建一个简单的用户模型,包含 usernamepassword 字段:

// app/model/user.ts

module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;

  const UserSchema = new Schema({
    username: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    status: { type: Number, default: 1 }, // 1: 启用, 0: 禁用
    createdAt: { type: Date, default: Date.now },
  });

  return mongoose.model('User', UserSchema, 'user'); // 第三个参数指定集合名称
};

4.2 创建 Order 模型(用于关联查询)

创建一个订单模型,包含 order_idtotal_price 字段:

// app/model/order.ts

module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;

  const OrderSchema = new Schema({
    order_id: { type: String, required: true },
    uid: { type: Number },
    total_price: { type: Number },
    createdAt: { type: Date, default: Date.now },
  });

  return mongoose.model('Order', OrderSchema, 'order');
};

4.3 多数据库模型定义

如果使用多数据库配置,需指定连接的数据库:

// app/model/user.ts (连接 db1)

module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;
  const conn = app.mongooseDB.get('db1'); // 指定数据库连接

  const UserSchema = new Schema({
    username: { type: String, required: true },
    password: { type: String, required: true },
  });

  return conn.model('User', UserSchema);
};

5. 实现 CRUD 操作

在 Egg.js 中,建议将数据库操作逻辑放在 service 层,控制器(controller)调用 service 处理业务逻辑。

5.1 创建 Service

创建 app/service/user.ts 来处理用户相关的数据库操作:

// app/service/user.ts

const Service = require('egg').Service;

class UserService extends Service {
  // 查询所有用户
  async getUserList() {
    return await this.ctx.model.User.find({});
  }

  // 添加用户
  async addUser(userData) {
    const user = new this.ctx.model.User(userData);
    return await user.save();
  }

  // 更新用户
  async updateUser(id, updateData) {
    return await this.ctx.model.User.updateOne(
      { _id: id },
      { $set: updateData }
    );
  }

  // 删除用户
  async deleteUser(id) {
    return await this.ctx.model.User.deleteOne({ _id: id });
  }
}

module.exports = UserService;

5.2 创建 Controller

创建 app/controller/user.ts 来处理 HTTP 请求:

// app/controller/user.ts

const Controller = require('egg').Controller;

class UserController extends Controller {
  // 获取用户列表
  async index() {
    const { ctx } = this;
    const userList = await ctx.service.user.getUserList();
    ctx.body = {
      code: 200,
      data: userList,
      msg: '获取用户列表成功',
    };
  }

  // 添加用户
  async create() {
    const { ctx } = this;
    const userData = ctx.request.body;
    const result = await ctx.service.user.addUser(userData);
    ctx.body = {
      code: 200,
      data: result,
      msg: '添加用户成功',
    };
  }

  // 更新用户
  async update() {
    const { ctx } = this;
    const { id } = ctx.params;
    const updateData = ctx.request.body;
    const result = await ctx.service.user.updateUser(id, updateData);
    ctx.body = {
      code: 200,
      data: result,
      msg: '更新用户成功',
    };
  }

  // 删除用户
  async destroy() {
    const { ctx } = this;
    const { id } = ctx.params;
    const result = await ctx.service.user.deleteUser(id);
    ctx.body = {
      code: 200,
      data: result,
      msg: '删除用户成功',
    };
  }
}

module.exports = UserController;

创建 app/controller/csrf.ts,返回 CSRF 令牌

// app/controller/csrf.ts

const Controller = require('egg').Controller;

class CsrfController extends Controller {
  async get() {
    const { ctx } = this;
    ctx.body = {
      csrfToken: ctx.csrf, // 获取 CSRF 令牌
    };
  }
}
module.exports = CsrfController;

如果你的应用是 API 服务或正在开发阶段,可以临时禁用 CSRF 保护。

// config/config.default.ts

module.exports = appInfo => {
  const config = exports = {};

  config.security = {
    csrf: {
      enable: false, // 禁用 CSRF 保护
    },
  };

  return config;
};

针对特定路由禁用 CSRF:

// app/router.ts

module.exports = app => {
  const { router, controller } = app;
  router.post('/users', controller.user.create, { csrf: false }); // 禁用 CSRF
};

5.3 配置路由

app/router.ts 中定义路由:

// app/router.ts

module.exports = app => {
  const { router, controller } = app;
  router.get('/csrf', controller.csrf.get); // 获取 CSRF 令牌
  router.get('/users', controller.user.index); // 获取用户列表
  router.post('/users', controller.user.create); // 添加用户
  router.put('/users/:id', controller.user.update); // 更新用户
  router.delete('/users/:id', controller.user.destroy); // 删除用户
};

6. 高级功能:关联查询与聚合管道

6.1 关联查询($lookup)

假设有一个 order_item 集合与 order 集合关联,可以使用 $lookup 进行关联查询:

// app/controller/order.ts

const Controller = require('egg').Controller;

class OrderController extends Controller {
  async index() {
    const { ctx } = this;
    const orderResult = await ctx.model.Order.aggregate([
      {
        $lookup: {
          from: 'order_item', // 关联的集合名
          localField: 'order_id',
          foreignField: 'order_id',
          as: 'items',
        },
      },
      {
        $match: {
          total_price: { $gte: 90 }, // 过滤条件
        },
      },
    ]);

    ctx.body = {
      code: 200,
      data: orderResult,
      msg: '获取订单列表成功',
    };
  }
}

module.exports = OrderController;

6.2 分页查询

service 层实现分页查询:

// app/service/user.ts
async getUserList(page = 1, pageSize = 10) {
  const skip = (page - 1) * pageSize;
  const users = await this.ctx.model.User.find({})
    .sort({ createdAt: -1 }) // 按创建时间倒序
    .skip(skip)
    .limit(pageSize);
  return users;
}

7. 启动项目

运行以下命令启动 Egg.js 项目:

npm run dev

访问 http://localhost:7001/users 测试 API。可以使用 Postman 或 cURL 发送 POST、PUT、DELETE 请求测试其他功能。

Postman 测试

image

添加用户

{
  "username": "john_doe1",
  "password": "password1231",
  "status": 1
}

image

image


8. 注意事项

  • 错误处理:在生产环境中,建议在 servicecontroller 中添加 try-catch 块处理异常。
  • 安全性:避免在配置文件中硬编码敏感信息(如 MongoDB 密码),可使用环境变量(如 process.env.MONGO_URL)。
  • 性能优化:为常用查询字段添加索引(如 username: { index: true })。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值