用 Mongoose 插件记录Node.js API 日志

2019-09-11 admin

作者:Shailesh Shekhawat

翻译:疯狂的技术宅

原文:https://www.freecodecamp.org/…

未经允许严禁转载

clipboard.png

本教程需要事先了解mongoose 对象关系映射(ORM)技术

介绍

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

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

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

Mongoose 中的插件是什么?

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

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

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

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

  • Action: 按照它的名称,这是 API 的一个动作过程,无论是 createupdatedelete还是别的什么。
  • Category: API 类别。例如医生和患者。它更像是一个阶级。
  • **CreatedBy:**正在使用或调用 API 的用户。
  • Message: 你可以在此处包含你想要显示的任何类型的消息,这些消息在调试过程中有意义或有帮助。
  • Diff: 这是主要属性,它是两个 JSONdiff

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

const mongoose = require('mongoose')
const Schema = mongoose.Schema
const { ObjectId } = Schema

const LogSchema = new Schema({
  action: { type: String, required: true },
  category: { type: String, required: true },
  createdBy: { type: ObjectId, ref: 'Account', required: true },
  message: { type: String, required: true },
  diff: { type: Schema.Types.Mixed },
},{
  timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' },
})

LogSchema.index({ action: 1, category: 1 })

module.exports = mongoose.model('Log', LogSchema)

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

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

我们称之为 diff.js

const _ = require('lodash')

exports.getDiff = (curr, prev) => {
  function changes(object, base) {
    return _.transform(object, (result, value, key) => {
      if (!_.isEqual(value, base[key]))
        result[key] = (_.isObject(value) && _.isObject(base[key])) ?                 changes(value, base[key]) : value
    })
 }
 return changes(curr, prev)
}

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

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

  • _.transform: 它是数组 .reduce 的替代品。它会迭代你对象的 keysvalues。它提供了一个 accumulator,是第一个参数。 result 是累加器,是可变的。
  • _.isEqual: 在两个值之间进行深度比较,以确定它们是否相等。

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

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

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

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

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

const _ = require('lodash')
const LogSchema = require('../models/log')
const { getDiff } = require('../utils/diff')

const plugin = function (schema) {
  schema.post('init', doc => {
    doc._original = doc.toObject({transform: false})
  })
  schema.pre('save', function (next) {
    if (this.isNew) {
      next()
    }else {
      this._diff = getDiff(this, this._original)
      next()
    }
})

  schema.methods.log = function (data)  {
    data.diff = {
      before: this._original,
      after: this._diff,
    }
    return LogSchema.create(data)
  }
}

module.exports = plugin

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

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

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

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

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

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

在你的主server.jsapp.js中:

初始化全局 plugin 以便它可用于所有模式。你还可以通过在架构模型中初始化它来将其用于特定架构。

const mongoose = require('mongoose')

mongoose.plugin(require('./app/utils/diff-plugin'))

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

const User = require('../models/user')

exports.updateUser = (req, res, next) => {
  return User.findById(req.params.id)
    .then(user => {
        if (!user)
           throw new Error('Target user does not exist. Failed to update.')
       const { name } = req.body
       if (name) user.name = name
       return user.save()
     })
     .then(result => {
       res.json(result)
       return result
     })
     .catch(next)
     .then(user => {
         if (user && typeof user.log === 'function') { 
            const data = {
              action: 'update-user',
              category: 'users',
              createdBy: req.user.id,
              message: 'Updated user name',
         }
         return user.log(data)
     }
     }).catch(err => {
         console.log('Caught error while logging: ', err)
       })
}

结论

在本教程中,你学习了如何创建 Mongoose 插件并用它来记录 API 中的 changes。你可以使用插件执行更多操作来构建健壮的 Node.js 程序。


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


[转载]原文链接:https://segmentfault.com/a/1190000020356557

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-74864.html

文章标题:用 Mongoose 插件记录Node.js API 日志

相关文章
JS中的语音合成——Speech Synthesis API
JS中的语音合成——Speech Synthesis API 简介 HTML5中和Web Speech相关的API实际上有两类,一类是“语音识别(Speech Recognition)”,另外一个就是“语音合成(Speech Synthes...
2018-05-17
Node.js学习(1)----HTTP服务器与客户端
Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端。http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js 下层 C++部分实现,而接口由 Jav...
2015-11-12
使用jspdf生成pdf报表
由于前台html已经动态生成报表,而且,前台有一个功能,一个date range组件,当你拖动的时候,报表会在不提交到后台的情况下动态变化。 因此需要用到js生成生报表: 用到的组件: jquery.js jspdf.js canvg.js...
2017-03-25
梳理前端开发使用eslint-prettier检查和格式化代码
问题痛点 在团队的项目开发过程中,代码维护所占的时间比重往往大于新功能的开发。因此编写符合团队编码规范的代码是至关重要的,这样做不仅可以很大程度地避免基本语法错误,也保证了代码的可读性。 对于代码版本管理系统(svn 和 git或者其他)...
2018-05-07
如何为高负载网络优化Nginx 和 Node.js?
译者:AlfredCheung 在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对。他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器的C10K瓶颈。预设的配置已经可以获得很高的并发,不过,...
2015-11-12
jQuery中DOM树操作之使用反向插入方法实例分析
本文实例讲述了jQuery中DOM树操作之使用反向插入方法。分享给大家供大家参考。具体分析如下: 使用反向插入方法 这里我们先把创建的内容插人到元素前面,然后再把同一个元素插人到文档 中的另一个位置。通常,当在jQuery中操作元素时,利用...
2015-11-13
React Native 用JavaScript编写原生ios应用
ReactNative 可以基于目前大热的开源JavaScript库React.js来开发iOS和Android原生App。而且React Native已经用于生产环境——Facebook Groups iOS 应用就是基于它开发的。 Re...
2015-11-12
Bootstrap BootstrapDialog使用详解
这里有两种展现方式 写在前面:首先你要引入的库有 css : bootstrap.min.css bootstrap-dialog.css js : jquery-1.11.1.min.js bootstrap.min.js bootstr...
2017-03-16
ASP.NET 2.0 AJAX应用程序设计
ASP.NET Aiax技术是一种实现异步(Asynchronous)网络应用的技术,它被整合在ASP.NET 2.0之中,是As P.NET的一种扩展技术。通过ASENETAjax技术,开发人员或程序员可以将Web服务器控件和客户端脚本结...
2015-11-14
vue-awesome-swiper的使用以及API整理
一、先说一个看关于vue-awesome-swiper的一个坑 vue项目的package.json中显示的<span style=“color: orange;”>“vue-awesome-swiper”: “^2.5.4”&...
2018-04-26
回到顶部