koa html中添加数据,从零开始的Koa实战(6)插入数据

元叶秋
2023-12-01

我们的系统需要支持浏览和查找数据,或者新增和创建数据,为了更高效地存取信息,网站将使用到数据库。

经过前面的实战,我们已经有了下面的目录结构:

koa-blog

├── .env.example

├── .env

├── .gitignore

├── app

│ ├── middleware

│ │ └── logger.js

│ ├── router

│ │ ├── home.js

│ │ └── index.js

│ ├── util

│ │ └── log_format.js

│ └── view

│ ├── 404.html

│ └── index.html

├── app.js

├── config

│ ├── custom-environment-variables.json

│ ├── default.json

│ └── production.json

├── package.json

└── README.md

下面我们开始使用 Mongoose 来操作 MongoDB 数据库,并且将逐一创建 model 、 service、controller 。

关于Mongoose

Koa 应用支持多款数据库,从而可以执行新建(Create)、读取(Read)、更新(Update)和删除(Delete)操作 (CRUD) 。我们这里准备使用 MongoDB 作为数据库。

与数据库交互的方式

直接使用数据库的原生查询语言(如SQL、MongoDB API )

使用对象数据模型(Object Data Model,简称 ODM)或对象关系模型(Object Relational Model,简称 ORM)。 ODM / ORM 能将网站中的数据表示为 JavaScript 对象,然后将它们映射到底层数据库。一些 ORM 只适用某些特定数据库,还有一些是普遍适用的。

了解以上这些,我们来介绍今天的主角 Mongoose ,它是一款为异步工作环境设计的 MongoDB 对象建模工具。

安装Mongoose

$ npm install mongoose --save

安装 Mongoose 会添加 MongoDB 包括数据库驱动程序在内的所有依赖项,再加上我们在前面的实战安装并设置好了 MongoDB ,现在可以直接使用 Mongoose 连接数据库。

连接MongoDB

可以使用 require() 引入 mongoose ,并通过 mongoose.connect() 连接到本地数据库,但是为了方便管理,我们还是单独建立一个 plugin.js 文件,连接数据库:

// config/plugin.js

const mongoose = require('mongoose');

const config = require('config');

const dbConfig = config.get('Database');

exports.mongooseConnect = (request, response) => {

mongoose.connect(`mongodb://${dbConfig.user}:${dbConfig.password}@${dbConfig.host}:${dbConfig.port}/${dbConfig.dbName}?authSource=${dbConfig.dbName}`);

let db = mongoose.connection;

db.on('error', () => {

console.log('Mongoose连接错误: ' + err);

});

db.once('open', (callback) => {

console.log(`Mongoose连接到${dbConfig.dbName}`);

});

}

然后在 app.js 引入 config/plugin.js:

// app.js

require('dotenv-safe').config(); // 只需要引入一次

const Koa = require('koa');

const config = require('config'); // 引入config

const appConfig = config.get('App'); // 直接使用 config 获取App的配置

const apiPrefix = config.get('Router.apiPrefix'); // 可以通过Router.apiPrefix获取具体的值

const dbConfig = config.get('Database');

+ const { mongooseConnect } = require('./config/plugin');

+ mongooseConnect();

// ...

启动服务 npm start 即可看到数据库连接成功:

服务已经启动,访问:http://localhost:3001/api

Mongoose连接到koaBlog

创建Schema

数据库的模型使用 Schema 接口进行定义,在 mongoose 中,所有的东西都从 Schema 中衍生出来。 Schema 可以定义每个文档中存储的字段及字段的验证要求和默认值。

我们先来定义一个Schema(模式),在 app 目录新建一个文件夹 model ,再在其中建一个文件 article.js ,准备通过它创建文章的模式 :

// app/model/article.js

// 引入 Mongoose

const mongoose = require('mongoose');

// 定义一个模式

const Schema = mongoose.Schema;

const ArticleSchema = new Schema({

title: { // 标题

type: String,

required: true

},

author: { type: Schema.Types.ObjectId, ref: 'User' }, // 作者

content: String, // 正文

status: { // 1 未发布 2 发布

type: Number,

default: 1

},

summary: String, // 简介

cover: String, // 封面

publishDate: Date, // 发布时间

}, {

timestamps: { // 使用时间戳

createdAt: 'createDate', // 将创建时间映射到createDate

updatedAt: 'updateDate' // 将修改时间映射到updateDate

}

});

// 使用populate查询作者的信息

ArticleSchema.pre('findOne', function () {

this.populate('author', '_id name sex avatarUrl');

});

上面的代码片段中定义了一个简单的模式。首先引入 mongoose ,然后使用 Schema 构造器创建一个新的模式实例,使用构造器的对象参数定义各个字段、类型以及默认值。并且使用了 mongoose 提供的 timestamps 设置了创建时间和修改时间,以后我们创建和修改文档,这些时间会自动变更。

创建Model

定义模型(model)类后,可以使用它们来创建、更新或删除记录,以及通过查询来获取所有记录或特定子集。

使用 mongoose.model('集合别名', 模式) 方法从模式创建模型:

// app/model/article.js

// 引入 Mongoose

const mongoose = require('mongoose');

// 定义一个模式

const Schema = mongoose.Schema;

const ArticleSchema = new Schema({

// ...

});

// 使用populate查询作者的信息

ArticleSchema.pre('findOne', function () {

this.populate('author', '_id name sex avatarUrl');

});

+ module.exports = mongoose.model('Article', ArticleSchema);

创建Service

在上面的实战中,我们已经创建好了模型(model),接下可以通过 model 实例调用 save() 来向数据库新增文档。这些方法都是 mongoose 提供给的。

为了方便以后抽出通用的方法操作(CRUD),这里新增一个通用的 service 来对模型进行调用。

首先新建 service 目录,创建 base.js 文件,这个文件将处理一些通用的 model 调用逻辑:

// app/service/base.js

class Service {

constructor(model) {

this.model = model

}

// 创建记录

create(data) {

return this.model(data).save()

}

}

module.exports = Service;

接着我们将创建新的 service 文件: app/service/article.js ,创建一个 class 进行导出,完整代码如下:

// app/service/article.js

const articleModel = require('../model/article');

const Service = require('./base');

class ArticleService extends Service {

constructor() {

super(articleModel)

}

// ...

}

module.exports = new ArticleService();

当然,还需要将 service 导出,以提供 controller 使用,因此在 app/service 目录创建 index.js 文件,将目录里面的 service 都导出来:

// app/service/index.js

const article = require('./article');

module.exports = {

article

};

到这里,我们的 service 创建完毕,接下来需要来调用 service 进行数据操作。

创建Controller

Controller(控制器)是应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。接下来的实战中,我们将创建 controller 向 service 发送数据。

首先创建 app/controller 目录和对应的文件 app/controller/index.js 、 app/controller/article.js :

// app/controller/article.js

const { article } = require("../service"); // 引入service

class ArticleController {

async create(ctx) {

try {

const newArticle = await article.create({

title: "第一条数据",

content: "从零开始的koa实战",

summary: "实战"

});

ctx.body = newArticle;

} catch (err) {

ctx.body = err;

throw new Error(err);

}

}

}

module.exports = new ArticleController();

上面的代码中,我们先固定的创建一条数据,title 、 content 、 summary 都是固定的值。

ArticleController 使用了 service 定义的 create 方法来向数据库创建记录,并且我们依照 ArticleSchema 定义的数据模型进行传参。接着,将 ArticleController 导出:

// app/controller/index.js

const article = require('./article');

module.exports = {

article,

};

修改路由

前面已经将新增数据的处理逻辑对应到了 controller,接下来我们修改 routes/index.js 的路由设置,让请求能够指定到对应的 controller 上。在下面的代码中,我们暂时使用 get 类型来做测试,但是建议遵循RESTful风格来进行设计:

// app/router/index.js

const Router = require('koa-router');

const config = require('config'); // 引入config

const apiPrefix = config.get('Router.apiPrefix');

const router = new Router();

router.prefix(apiPrefix); // 设置路由前缀

const home = require('./home');

+ const { article } = require('../controller'); // 引入controller

const index = async (ctx, next) => {

await ctx.render('index', {title: 'Index', link: 'home'});

};

router.get('/', index);

router.get('/index', index);

+ router.get('/article', article.create);

router.use('/home', home.routes(), home.allowedMethods()); // 设置home的路由

module.exports = router;

我们将路由的 /article 对应到了 articleController 的 create 方法,当重启服务之后,在浏览器访问: http://localhost:3000/api/article ,可以看到已经创建了一条数据。页面中显示的数据如:

{"status":1,"_id":"5ef204b5b40da108dc47ae30","title":"第一条数据","content":"从零开始的koa实战","summary":"实战","createDate":"2020-06-23T13:33:41.858Z","updateDate":"2020-06-23T13:33:41.858Z","__v":0}

到这里,我们已经能够通过请求对MongoDB数据库进行数据插入,以后还将继续完善各项逻辑。

参考资料:

下一步,我们来以RESTful风格设计一个接口,使用postman来调用,从而提供用户注册API。

 类似资料: