Node.js 蚕食计划(六)—— MongoDB + Koa 入门

一、安装 MongoDB

1. 在 Windows 环境下安装:

// Windows 7 / Server 2008 R2 以上的版本

打开官网链接 https://www.mongodb.com/try/download/community

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第1张图片

在页面中依次选择 On-Premises => MongoDB Communtiy Server,然后选择 Platform 为 Windows,最后下载并执行安装包

 

1. 在 MacOS 安装: 

也可以按照上面的方法下载安装包,或者选择 Download 按钮旁的 Copy Link,通过 curl 命令安装

不过还有另一种不需要打开 MongoDB 官网的办法:直接使用 brew 安装(参考链接)

首先 tab 仓库

brew tap mongodb/brew

然后安装社区版本

brew install mongodb-community

安装的时候会自动创建配置文件:

  • 配置文件: /usr/local/etc/mongod.conf
  • 日志目录: /usr/local/var/log/mongodb
  • 数据目录: /usr/local/var/mongodb

可以用 mongod --version 命令来检查是否安装成功

如果能正常显示当前版本,就说明安装成功,可以直接进入下一节

 

如果提示 "command not found: mongod" ,就得手动配置环境变量

需要先找到 mongod 的安装位置,由于安装的版本不同,路径不会完全一致,可以一步一步的来找:

先进入 Cellar 目录:

cd /usr/local/Cellar

然后通过 ls 命令查看当前目录下的文件,然后进入带有 mongodb 的文件夹,然后逐步深入,直到进入 bin 文件夹,使用 pwd 命令查看完整路径

记下这个路径备用,打开环境变量配置文件

vim ~/.bash_profile

添加一行变量(把路径改成自己的路径)

export PATH=/usr/local/Cellar/mongodb-community/4.2.8/bin:${PATH}}

保存文件,执行以下命令

source ~/.bash_profile

然后就可以使用 mongod 命令了

 

 

二、启动 MongoDB

如果直接启动

mongod

会直接报错 Data directory /data/db not found

这是因为使用不带参数的 mongod 命令会使用默认的数据目录 /data/db

如果使用之前创建的配置文件启动就不会有问题:

mongod --config /usr/local/etc/mongod.conf

如果觉得这样的启动命令很累赘,就创建一个 /data/db 目录

sudo mkdir -p /data/db

然后就能使用 mongod 命令启动了,

// 如果遇到 Address already in use 这个错误,是因为端口号占用,清理对应端口的 pid 即可

可以在浏览器访问 localhost:27017 确认是否成功启动

如果需要关闭服务器,可以使用 Crtl + C 组合键

 

这个启动 mongod 的终端可以放在一边了,新起一个终端,打开 MongoDB shell

mongo

注意这个命令不是 mongod

在启动的 shell 里面输入 help,查看可用的命令

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第2张图片

如果不想使用命令行来操作 MongoDB,可以使用可视化工具,比如 Robomongo、Nosqlclient、Navicat

 

 

三、MongoDB 创建数据

接下来在 MongoDB 中插入数据,首先创建一个数据库

use Movie

这里创建了一个名为 Movie 的数据库,但这时的 Movie 数据库还没有数据,所以 show dbs 不会列出刚才创建的数据库

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第3张图片

 在当前数据库中创建一个集合,并插入一条数据

db.createCollection("movies")
db.movies.insert({"name":"让子弹飞","years":"2010","director": ["姜文"]})

注意: 和创建数据库类似,在 MongoDB 中,创建集合后要再插入一个文档,集合才会真正创建

当插入了具体的数据之后,数据库才算创建完成,接下来了解一下基本的增删改查

 

1. 新增数据

在 MongoDB 中可以使用 insert 向集合插入数据,每条新建的数据都会自动生成一个主键 _id

使用 insert 插入数据时,如果没有携带主键 _id,则新增数据;

如果携带了 _id 且 _id 没有重复,则新增一条自带 _id 的数据(不会自动生成 _id);

如果携带了 _id 且 _id 冲突,则抛出“主键重复”的错误,保存失败。

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第4张图片

 

2. 查询数据

在 MongoDB 中查询数据一般使用 find 方法

db.movies.find().pretty()

这里的 pretty() 用来格式化查询结果

在查询条件中,还可以加入条件判断

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第5张图片

 

3. 更新数据

在 MongoDB 中使用 update 和 replaceOne 来更新集合中的文档

其中 update() 可以接收三个参数

第一个参数为查询条件,和上面的 find 类似;

第二个参数为操作符,比如 $set 用来设置新属性;

第三个参数为配置项,暂时不提。

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第6张图片

这里我先新增了一条数据,然后通过 update 修改了这条数据的 name

可以看到,只有 name 被修改了,years 并没有发生变化,也就是说 update()$set 只会合并相应的字段

如果需要替换整条数据,可以用 replaceOne()

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第7张图片

  

4. 删除数据

可以使用 remove 来删除集合中的数据

该方法和 find 类似,都是接受一个查询条件,然后从集合中删除查询到的文档

remove 的 query 参数是必填的,如果往 remove 方法中传入的查询条件为空对象 {},会删除整个集合的数据

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第8张图片

另外, 可以使用 drop 来删除集合,dropDatabase 来删除数据库

db.collection.drop()
db.dropDatabase()

关于 MongoDB 的介绍就到这里,深入了解可以参考 MongoDB 中文网 

 

 

四、在 Koa 中连接 MongoDB

先创建一个 Koa 项目,可以参考之前的文章《Node.js 蚕食计划(五)—— Koa 基础项目搭建》

在项目的根目录创建一个 mongodb 目录,然后在该目录下新建  config.js,用来保存一些数据库常量配置

// /mongodb/config.js

const dbUrl = 'mongodb://127.0.0.1:27017'; // 数据库地址
const dbName = 'Movie'; //数据库名称

module.exports = {
  dbUrl,
  dbName
}

然后安装 mongodb 中间件

yarn add mongodb

在 mongodb 目录下创建一个 index.js,使用中间件连接 MongoDB 数据库

// /mongodb/index.js

const { MongoClient, ObjectID}  = require('mongodb');
const { dbUrl, dbName } = require('./config');

// 连接数据库
MongoClient.connect(dbUrl, (err, client) => {
    console.log("Connected successfully to server");
    const db = client.db(dbName);
    // db.close(); // 关闭连接
});

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第9张图片

我的项目结构是这样的,其中 app.js 是入口文件

可以在 app.js 中 require('./mongodb') 直接引入刚才的 index.js,检查一下是否能够正常连接数据库

启动项目,如果在 MongoDB 的终端看到连接的提示,则表示成功连接数据库

 

 

五、封装 MongoDB 类

实际场景中肯定不会每次查询都调用一次数据库,所以需要封装一个类,通过类的实例来操作数据库 

// /mongodb/index.js

const { MongoClient, ObjectID } = require("mongodb");
const Config = require("./config");

class Db {
  static getInstance() {
    // 单例模式 解决多次实例化 实例不共享的问题
    if (!Db.instance) {
      Db.instance = new Db();
    }

    return Db.instance;
  }

  constructor() {
    this.dbClient = ""; //db对象
    this.connect(); // 实例化的时候就连接数据库
  }

  connect() {
    // 连接数据库
    return new Promise((resolve, reject) => {
      if (!this.dbClient) {
        //解决数据库多次连接的问题
        MongoClient.connect(Config.dbUrl, { useUnifiedTopology: true }, (err, client) => {
          if (err) {
            reject(err);
            return;
          }
          this.dbClient = client.db(Config.dbName);
          resolve(this.dbClient);
        });
      } else {
        resolve(this.dbClient);
      }
    });
  }

  //查找操作 collection:表名 json:查找条件
  find(collection, json) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        let result = db.collection(collection).find(json);
        result.toArray((err, docs) => {
          if (!err) {
            resolve(docs);
          } else {
            reject(err);
          }
        });
      });
    });
  }

  //新增操作
  insert(collection, json) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        db.collection(collection).insertOne(json, (err, result) => {
          if (!err) {
            resolve(result);
          } else {
            reject(err);
          }
        });
      });
    });
  }

  //修改操作
  update(collection, json1, json2) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        db.collection(collection).updateOne(
          json1,
          {
            $set: json2,
          },
          (err, result) => {
            if (!err) {
              resolve(result);
            } else {
              reject(err);
            }
          }
        );
      });
    });
  }

  //删除操作
  delete(collection, json) {
    return new Promise((resolve, reject) => {
      this.connect().then((db) => {
        db.collection(collection).removeOne(json, (err, result) => {
          if (!err) {
            resolve(result);
          } else {
            reject(err);
          }
        });
      });
    });
  }

  //在进行查询或者删除操作的时候,我们一般都会通过id去进行操作,但是我们直接使用传递过来的id是不起作用的,需要使用mongodb提供的ObjectID方法,生成一个新的id去查询。
  getObjectID(id) {
    return new ObjectID(id);
  }
}

module.exports = Db.getInstance();

// 代码摘自 https://juejin.im/post/5e4765626fb9a07cad3b93dc#heading-24

封装好了,在 app.js 试试

//...
const bodyParser = require('koa-bodyparser');
const DB = require('./mongodb');
//... app.use(bodyParser()); router.post('/save', async(ctx, next) => { const form = ctx.request.body; console.log('form------>', form); const result = await DB.insert('movies', form); // 新增 ctx.body = result; }); router.get('/list', async(ctx, next) => { const result = await DB.find('movies', {}); // 查询 ctx.body = result; }); //...

上面引入了 koa-bodyparser 来处理 POST 请求的参数

然后写了一个新增数据的 post 接口 /save,和查询数据的 get 接口 /list

接下来先用 PostMan 测试一下 /save 接口

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第10张图片

这里传的参数是 JSON 格式,需要在 Headers 中设置 Content-Type 为 application/json

如果设置为 application/x-www-form-urlencoded,就需要用 querystring 转码

 

保存成功之后,再试试 /list 接口

Node.js 蚕食计划(六)—— MongoDB + Koa 入门_第11张图片

到这里一个简单的后端服务就搭好了

但这里我们直接使用了 mongodb 中间件来连接数据库,对数据库的操作比较原始

一个工程化的后端项目,通常会设计 Controller 来管理 API,还会通过 Schema 来规范集合

这些都可以通过 使用 mongoose 来实现,在后面的文章中会介绍

 

参考资料:

《MongoDB 中文手册》

《koa2 + jwt + mongodb入门实战》

你可能感兴趣的:(Node.js 蚕食计划(六)—— MongoDB + Koa 入门)