ПЕРЕСМОТРЕННЫЙ ВОПРОС
Я пересмотрел вопрос в надежде получить более четкий ответ.
Я пытаюсь обработать данные в ExpressJS , исходя из входящих req.body
и существующих данных в таблице.
Я получаю req.body
, который содержит JSON список обновленных полей. Некоторые из этих полей хранятся как JSONB в Postgres. Если входящим полем является JSONB, то форма (внешний код), который делает запрос, уже запустила jsonpatch.compare()
для генерации списка патчей, и именно эти патчи, а не полные значения, передаются. любые не-JSONB-значения, входящие значения просто необходимо передать в запрос UPDATE
.
У меня есть рабочая версия, как показано ниже, которая делает вид, что существующие значения JSONB в таблице равны NULL. Понятно, что это НЕ то, что нужно. Мне нужно вытащить значения из БД. Версия без запроса текущих значений и минимальный маршрутизатор выглядят так:
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), мне нужны выборка, cal c и обновление, чтобы она выполнялась как ОДИН ТРАНЗАКЦИЯ. Мой план:
НАЧАТЬ транзакцию
Запрос Postgres для текущего значения строки на основе входящего id
Для любых полей JSONB примените исправление, чтобы сгенерировать правильное значение для этого поля в инструкции UPDATE.
Запустите инструкцию UPDATE с соответствующие значения параметров (либо из req.body
, либо из исправленной строки, в зависимости от того, является ли поле JSONB или нет)
COMMIT транзакции или ROLLBACK при ошибке.
Я пытался реализовать ответ от @midrizi; может быть, это только я, но комбинация ожидания и простого тестирования res
отправляет сервер в гиперпространство ... и заканчивается таймаутом.