【问题标题】:ES6 Async/Await, ExpressJS and Postgres transactionsES6 Async/Await、ExpressJS 和 Postgres 事务
【发布时间】:2020-04-11 15:16:51
【问题描述】:

修改后的问题

我已经修改了问题,希望得到更清晰的答案。


我正在尝试根据传入的req.body 和表中的现有数据处理 ExpressJS 中的数据。

我收到了一个req.body,其中包含更新字段的 JSON 列表。其中一些字段在 Postgres 中存储为 JSONB。如果传入字段是 JSONB,则发出请求的表单(外部代码)已经运行 jsonpatch.compare() 以生成补丁列表,并且传入的是这些补丁而不是完整值。对于任何非 JSONB 值,传入的值只需要传递给 UPDATE 查询。

我有一个工作版本,如下所示,它假装表中现有的 JSONB 值是 NULL。显然,这不是所需要的。我需要从数据库中提取值。 non-querying-of-current-values 版本和最低限度的路由器,如下所示:

const express = require('express')
const bodyParser = require('body-parser')
const SQL = require('sql-template-strings')
const { Client } = require('pg')
const dbConfig = require('../db')
const jsonpatch = require('fast-json-patch')

const FormRouter = express.Router()

I have some update code:

````javascript
const patchFormsRoute = (req, res) => {
  const client = new Client(dbConfig)
  const { id } = req.body
  const parts = []
  const params = [id]

  // list of JSONB fields for the 'forms' table
  const jsonFields = [
    'sections',
    'editors',
    'descriptions',
  ]

  // list of all fields, including JSONB fields in the 'forms' table
  const possibleFields = [
    'status',
    'version',
    'detail',
    'materials',
    ...jsonFields,
  ]

  // this is a DUMMY RECORD instead of the result of a client.query 
  let currentRecord = { 'sections':[], 'editors':[], 'descriptions':[] }

  possibleFields.forEach(myProp => {
    if (req.body[myProp] != undefined) {
      parts.push(`${myProp} = $${params.length + 1}`)
      if (jsonFields.indexOf(myProp) > -1) {
        val = currentRecord[myProp]
        jsonpatch.applyPatch(val, req.body[myProp])
        params.push(JSON.stringify(val))
      } else {
        params.push(req.body[myProp])
      }
    }
  })

  const updateQuery = 'UPDATE forms SET ' + parts.join(', ') + ' WHERE id = $1'

  client.connect()
  return client
    .query(updateQuery, params)
    .then(result => res.status(200).json(result.rowCount))
    .catch(err => res.status(400).json(err.severity))
    .then(() => client.end())
}

FormRouter.route('/')
  .patch(bodyParser.json({ limit: '50mb' }), patchFormsRoute)

exports.FormRouter = FormRouter

我保证,这是工作代码,几乎满足了我的需求。但是,我想用表中已有的数据替换虚拟记录,同时获取。我的问题是因为多个客户端可能同时更新一行(但查看 JSONB 值的正交元素),我需要获取、计算和更新作为单个事务发生。我的计划是:

  1. 开始交易

  2. 根据传入的id查询 Postgres 的当前行值

  3. 对于任何 JSONB 字段,应用补丁以在 UPDATE 语句中为该字段生成正确的值。

  4. 使用适当的参数值运行 UPDATE 语句(来自 req.body 或修补的行,具体取决于字段是否为 JSONB)

  5. COMMIT 事务,或 ROLLBACK 错误。

我已经尝试实施来自@midrizi 的答案;也许只有我一个人,但是等待和res 的简单测试相结合将服务器发送到超空间......并以超时结束。

【问题讨论】:

  • 为什么在 catch 后面有一个then
  • 确保无论发生什么都关闭客户端

标签: node.js postgresql async-await node-postgres


【解决方案1】:

如果有人还醒着,这是我的问题的有效解决方案。

TLDR; RTFM:A pooled client with async/await 减去池化(暂时)。

const patchFormsRoute = (req, res) => {
  const { id } = req.body
  // list of JSONB fields for the 'forms' table
  const jsonFields = [
    'sections',
    'editors',
    'descriptions',
  ]

  // list of all fields, including JSONB fields in the 'forms' table
  const possibleFields = [
    'status',
    'version',
    'detail',
    'materials',
    ...jsonFields,
  ]
  const parts = []
  const params = [id]

  ;(async () => {
    const client = await new Client(dbConfig)
    await client.connect()
    try {
      // begin a transaction
      await client.query('BEGIN')

      // get the current form data from DB
      const fetchResult = await client.query(
        SQL`SELECT * FROM forms WHERE id = ${id}`,
      )

      if (fetchResult.rowCount === 0) {
        res.status(400).json(0)
        await client.query('ROLLBACK')
      } else {
        const currentRecord = fetchResult.rows[0]

        // patch JSONB values or update non-JSONB values
        let val = []

        possibleFields.forEach(myProp => {
          if (req.body[myProp] != undefined) {
            parts.push(`${myProp} = $${params.length + 1}`)
            if (jsonFields.indexOf(myProp) > -1) {
              val = currentRecord[myProp]
              jsonpatch.applyPatch(val, req.body[myProp])
              params.push(JSON.stringify(val))
            } else {
              params.push(req.body[myProp])
            }
          }
        })

        const updateQuery =
          'UPDATE forms SET ' + parts.join(', ') + ' WHERE id = $1'

        // update record in DB
        const result = await client.query(updateQuery, params)

        // commit transaction
        await client.query('COMMIT')

        res.status(200).json(result.rowCount)
      }
    } catch (err) {
      await client.query('ROLLBACK')
      res.status(400).json(err.severity)
      throw err
    } finally {
      client.end()
    }
  })().catch(err => console.error(err.stack))
}

【讨论】:

    猜你喜欢
    • 2016-08-22
    • 1970-01-01
    • 2016-02-26
    • 2019-10-15
    • 1970-01-01
    • 2016-07-11
    • 2017-10-10
    • 2019-04-24
    相关资源
    最近更新 更多