【学习任务】尝试着实现最简单版本的 `mongoose`
976

描述

尝试着实现最简单版本的 mongoose

难度

4 星

需求

假定实现的小框架名为 SMDB (Simple MongoDB)。

要求实现如下能力:

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

// 注册一个 user Schema
const UserSchema = new smdb.Schema({
  account: String,
  password: String,
});

smdb.model('User', UserSchema);

// 得到一个 model
const UserModel = smdb.model('User');

// 连接数据库
smdb.connect('mongodb://localhost:27017/smdb-test').then(async () => {
  const user = new UserModel({
    account: '1',
    password: '2',
  });

  const res = await user.save();

  console.log('添加成功', res);

  const list = await UserModel.find();

  console.log('列表:', list);
}).catch(e => {
  console.log(e);
});

只需要实现以上功能,Schema 的属性定义,类型也只需要支持 String,其他非空等都不需要处理。

目的

为了更好的了解 mongoose 处理机制,培养工程思维,提升编码水平,以及脱离 mongoose 应该怎么去操作 MongoDB。

研究路线

首先要了解脱离 mongoose 后,怎么使用 node.js 去链接 MongoDB,并且操作 MongoDB。

node.js 有一个 mongodb 包,翻阅 mongoose 的源码或者观察 mongoose 项目的 package.json 会发现也使用了这个包,所以可以从这个包入手。

了解完这个包的API后,其实就是对他进行一个封装,对应的套用mongoose的模式即可。

实现

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

// mongodb 客户端操作工具库
const MongoClient = mongodb.MongoClient;

// 获取数据类型
const getType = (sth) => {
  const flag = Object.prototype.toString.call(sth);

  return flag.replace('[object ', '').replace(']', '');
};

// 放数据库实例 后续操作数据库都通过这个 db
let db = null;

// 连接数据库
const connect = (url) => {
  return new Promise((resolve, reject) => {
    MongoClient.connect(url, (err, client) => {
      if (err) {
        reject(err);
        return;
      }

      db = client.db();

      resolve(client);
    });
  });
};

// Schema 类
class Schema {
  schema = {};

  constructor(schema) {
    this.schema = schema;
  }
}

// 所有注册过的 model 都放在这里
const modelMap = {};
const model = (key, schemaInst) => {
  // 如果model已经存在,就返回已存在的 model
  if (modelMap[key]) {
    return modelMap[key];
  }

  // 如果model不存在 则创建一个
  modelMap[key] = class {
    // 放置 model 对应的 schema
    schema = schemaInst;
    // 创建新文档时候的数据
    data = {};

    // 静态方法,用于寻找所有文档
    static find() {
      return new Promise((resolve, reject) => {
        db
          .collection(`${key}s`)
          .find()
          .toArray((err, docs) => {
            if (err) {
              reject(err);
              return;
            }

            resolve(docs);
          });
      })
    }

    // 数据类型校验
    check() {
      for (let key of Object.keys(this.data)) {
        const type = this.schema.schema[key];

        if (!type.toString().includes(getType(this.data[key]))) {
          throw TypeError(`${key} 应该是 String 类型`);
        }
      }
    }

    // 构造函数
    constructor(data) {
      this.data = data;
      this.check();
    }

    // 保存
    save() {
      return new Promise((resolve, reject) => {
        db
          .collection(`${key}s`)
          .insertOne(this.data)
          .then((res) => {
            resolve(res.result);
          })
          .catch((err) => {
            reject(err);
          });
      });
    }
  };

  return modelMap[key];
};

module.exports = {
  connect,
  Schema,
  model,
};
我的作业
去发布

登录后即可发布作业,立即

全部作业

数据加载中...

意见反馈 帮助中心 APP下载
官方微信