用 Mongoose 插件记录Node.js API日志[每日前端夜话0xBD]

  本教程需要事先了解 mongoose 对象关系映射(ORM)技术【https://mongoosejs.com/】

介绍

随着程序的增长,日志记录成为跟踪所有内容的关键部分。它对于调试目的尤为重要。

现在已经有了 npm 的日志记录模块。这些模块可以将日志存储在不同格式或级别的文件中。我们将使用流行的ORM Mongoose 讨论 Node.js Express 程序中的 API 日志记录。

那么如何创建一个 Mongoose 插件,以更清洁的方式为你进行记录并简化 API 日志?

Mongoose 中的插件是什么?

在 Mongoose 中,模式是可插入的。插件就像一个函数,你可以在模式中使用它,并在模式实例上一次次地重用。

Mongoose 还提供全局插件,你可以将其用于所有模式。例如我们将会编写一个插件,它将创建两个 jsons的diff 并写入 mongodb。

步骤1:创建基本日志模式模型

让我们创建一个具有以下六个属性的基本日志模式:

  • Action: 按照它的名称,这是 API 的一个动作过程,无论是 * create、update、delete还是别的什么。

  • Category: API 类别。例如医生和患者。它更像是一个阶级。

  • CreatedBy:正在使用或调用 API 的用户。

  • Message: 你可以在此处包含你想要显示的任何类型的消息,这些消息在调试过程中有意义或有帮助。

  • Diff : 这是主要属性,它是两个 JSON 的 diff

如果你希望对自己的应用程序有意义,可以添加更多字段,也可以根据需要更改和升级架构。
这是我们的模型:models/log.js

1const mongoose = require('mongoose') 2const Schema = mongoose.Schema 3const { ObjectId } = Schema 4 5const LogSchema = new Schema({ 6  action: { type: String, required: true }, 7  category: { type: String, required: true }, 8  createdBy: { type: ObjectId, ref: 'Account', required: true }, 9  message: { type: String, required: true },10  diff: { type: Schema.Types.Mixed },11},{12  timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' },13})1415LogSchema.index({ action: 1, category: 1 })1617module.exports = mongoose.model('Log', LogSchema)

步骤2:编写一个函数来获得 2 个 JSON 之间的差异

所以下一步是你需要一个可重用的函数,它将动态创建两个 JSON 的 diff。

我们称之为 diff.js

 1const _ = require('lodash') 2 3exports.getDiff = (curr, prev) => { 4  function changes(object, base) { 5    return _.transform(object, (result, value, key) => { 6      if (!_.isEqual(value, base[key])) 7        result[key] = (_.isObject(value) && _.isObject(base[key])) ?                 changes(value, base[key]) : value 8    }) 9 }10 return changes(curr, prev)11}

我使用了 lodash,这是一个提供相同功能的受欢迎的库。

让我们分解上面的函数,看看发生了什么:

  • _.transform: 它是数组 .reduce 的替代品。它会迭代你对象的 keys 和 values。它提供了一个 accumulator,是第一个参数。result 是累加器,是可变的。

  • _.isEqual: 在两个值之间进行深度比较,以确定它们是否相等。

    isEqual:此方法支持比较数组、数组缓冲区、布尔值、日期对象、错误对象、映射、数字、对象、正则表达式、集合、字符串、符号和类型化数组。对象通过它们自己的方法比较,而不是通过继承的、可枚举的属性进行比较。函数和 DOM 节点则进行严格相等的比较,即使用 ===。

这里我们迭代每个对象的属性和值,并将它与旧对象进行比较。

如果当前对象的 value 不等于前一个对象中相同属性的值:base[key] 如果该值是对象本身,我们递归调用函数changes 直到它得到一个值,它最终将作为 result[key]=value 存储在 result 中。

步骤3:创建一个插件用来 diff 并将其保存到数据库

现在我们需要跟踪数据库中的前一个 document 并在保存到 mongodb 之前创建一个 diff。

 1const _ = require('lodash') 2const LogSchema = require('../models/log') 3const { getDiff } = require('../utils/diff') 4 5const plugin = function (schema) { 6  schema.post('init', doc => { 7    doc._original = doc.toObject({transform: false}) 8  }) 9  schema.pre('save', function (next) {10    if (this.isNew) {11      next()12    }else {13      this._diff = getDiff(this, this._original)14      next()15    }16})1718  schema.methods.log = function (data)  {19    data.diff = {20      before: this._original,21      after: this._diff,22    }23    return LogSchema.create(data)24  }25}2627module.exports = plugin

在 Mongoose 中,有不同的钩子可用。现在我们需要使用架构上可用的 init 和 save 方法。

this.isNew():如果你正在创建新文档,那么只需返回 next()中间件。

在 schema.post('init') 的 toObject()中:

1doc._original = doc.toObject({transform: false})

Mongoose Model 继承自 document,它有一个 toObject() 方法。它将 document 转换为 Object()和transform:false是为了不允许转换返回对象。

步骤4:用法 - 如何在express.js API中使用

在你的主server.js或app.js中:

初始化全局 plugin 【https://mongoosejs.com/docs/plugins.html】以便它可用于所有模式。你还可以通过在架构模型中初始化它来将其用于特定架构。

1const mongoose = require('mongoose')23mongoose.plugin(require('./app/utils/diff-plugin'))

这是 user 更新 API 的基本示例:

 1const User = require('../models/user') 2 3exports.updateUser = (req, res, next) => { 4  return User.findById(req.params.id) 5    .then(user => { 6        if (!user) 7           throw new Error('Target user does not exist. Failed to update.') 8       const { name } = req.body 9       if (name) user.name = name10       return user.save()11     })12     .then(result => {13       res.json(result)14       return result15     })16     .catch(next)17     .then(user => {18         if (user && typeof user.log === 'function') { 19            const data = {20              action: 'update-user',21              category: 'users',22              createdBy: req.user.id,23              message: 'Updated user name',24         }25         return user.log(data)26     }27     }).catch(err => {28         console.log('Caught error while logging: ', err)29       })30}

结论

在本教程中,你学习了如何创建 Mongoose 插件并用它来记录 API 中的 changes。你可以使用插件执行更多操作来构建健壮的 Node.js 程序。
原文:https://www.freecodecamp.org/news/how-to-log-a-node-js-api-in-an-express-js-app-with-mongoose-plugins-efe32717b59/

更多相关文章

  1. 中国省市区地址三级联动jQuery插件
  2. [原]jQuery Tab插件,用于在Tab中显示iframe,附源码和详细说明
  3. 美元。针对简单的php, post返回对象
  4. 将JavaScript对象作为Dictionary 传递给C#WCF服务
  5. 分享27款非常棒的 jQuery 表单插件
  6. 通过],[和创建json对象来分割字符串
  7. 在Wordpress中包含一个github jquery插件
  8. 我通过jQuery-ajax创建了__PHP_Incomplete_Class对象此错误
  9. 如何从Python脚本向jQuery发送JSON对象?

随机推荐

  1. Shell脚本更改带变量的目录
  2. 初探Linux kernel之进程相关二
  3. 【Linux】CentOS7无法使用tab补全功能
  4. ARM11、OK6410_Linux、系统移植 和 驱动
  5. openfalcon - centos 5.5 + python 2.4 r
  6. RHEL6误安装RHEL7的包导致glibc被升级后
  7. 我如何在Linux和Python中监听“usb设备插
  8. Telnet套接字网关到Coldfusion事件网关,连
  9. Linux开发工具(gcc gdb make shell)——G
  10. Vue绑定内联样式问题