Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgres存储过程参数的JSON对象_Json_Postgresql_Stored Procedures - Fatal编程技术网

Postgres存储过程参数的JSON对象

Postgres存储过程参数的JSON对象,json,postgresql,stored-procedures,Json,Postgresql,Stored Procedures,有一个单页应用程序,它发送带有JSON有效负载的POST HTTP请求: {"product": { "name": "product A", "quantity": 100 }} 有一个Postgres数据库,其中包含表和存储过程: create table product { product_id serial primary key, name text, quantity numeric, description text } create function inse

有一个单页应用程序,它发送带有JSON有效负载的POST HTTP请求:

{"product": { "name": "product A", "quantity": 100 }}
有一个Postgres数据库,其中包含表和存储过程:

create table product {
  product_id serial primary key,
  name text,
  quantity numeric,
  description text
}

create function insert_product (product product) returns product as $$
  -- This function accepts a product type as an argument
有没有一种语言的解决方案可以放在服务器上,处理HTTP请求,调用存储过程,并自动将JSON对象转换为正确的Postgres行类型

在pseudo-Express.js中

app.post('/product', (req, res) =>
  db.query('select insert_product($1)', [convertToPostgresPlease(req.body.product)])
我不考虑解决方案:

  • 解构JSON对象并用茶匙将每个键输入Postgres 或在存储过程中处理JSON(SP应接受行类型)
  • 从Postgres模式复制信息(解决方案必须使用Postgres内省功能)
  • 手动连接
    ”(“+product.name+”,“+…”
我知道存储过程经常受到冷遇,但对于小项目,我真的认为它们很棒。SQL是处理数据的惊人DSL,Postgres足够先进,可以处理任何与数据相关的任务

在任何情况下,连接JSON HTTP请求和适当的SQL RDBMS的最简单方法是什么

找到解决方案(几乎):

  • (有效,但太神奇了)
  • (列表分析器,尚未尝试)

正如注释中提到的Abelisto,您可以使用
JSON\u-populate\u-record
/
JSONB\u-populate\u-record
将数据库函数中的JSON/JSONB参数转换为特定的表行。另一种方法是直接使用
->
->
操作符使用JSON变量来检索其co这样做的缺点是每个表的维护都有相当多的编码

您还可以从RESTful接口(例如)中获益

基于JSON的解决方案的另一个选择是简化大量小型表的操作,这些表的每个记录数不会超过几百条。这会造成性能损失,但对于一些行来说,这可能可以忽略不计

下面举例说明了PostgreSQL中JSON数据类型的功能以及支持JSON运算符的GIN索引。对于需要最高性能的数据,您仍然可以使用普通表和专用函数

例如:

CREATE TABLE public.jtables (
  table_id serial NOT NULL PRIMARY KEY,
  table_name text NOT NULL UNIQUE,
  fields jsonb
);

INSERT INTO public.jtables VALUES (default, 'product', '{"id": "number", "name": "string", "quantity": "number", "description": "string"}'::jsonb);

CREATE TABLE public.jdata (
  table_id int NOT NULL REFERENCES jtables,
  data jsonb NOT NULL
);

CREATE UNIQUE INDEX ON public.jdata USING BTREE (table_id, (data->>'id'));
CREATE INDEX ON public.jdata USING GIN (data);
您可以创建函数以通用JSON方式操作数据,例如:

CREATE FUNCTION public.jdata_insert(_table text, _data jsonb) RETURNS text AS
$BODY$
  INSERT INTO public.jdata 
  SELECT table_id, $2
  FROM public.jtables
  WHERE table_name = $1
  RETURNING (data)->>'id';
$BODY$ LANGUAGE sql;

CREATE FUNCTION public.jdata_update(_table text, _id text, _data jsonb) RETURNS text AS
$BODY$
  UPDATE public.jdata d SET data = jsonb_strip_nulls(d.data || $3)
  FROM public.jtables t
  WHERE d.table_id = t.table_id AND t.table_name = $1 AND (d.data->>'id') = $2
  RETURNING (d.data)->>'id';
$BODY$ LANGUAGE sql;
然后可以使用以下通用函数插入行:

SELECT public.jdata_insert('product', '{"id": 1, "name": "Product 1", "quantity": 10, "description": "no description"}'::jsonb);
SELECT public.jdata_insert('product', '{"id": 2, "name": "Product 2", "quantity": 5}'::jsonb);
SELECT public.jdata_update('product', '1', '{"description": "test product"}'::jsonb);
并且可以使用现有索引以多种方式查询其数据:

SELECT * FROM public.jdata WHERE table_id = 1 AND (data->>'id') = '1';
SELECT * FROM public.jdata WHERE table_id = 1 AND data @> '{"quantity": 5}'::jsonb;
SELECT * FROM public.jdata WHERE table_id = 1 AND data ? 'description';
视图可以简化查询:

CREATE VIEW public.vjdata AS
SELECT d.table_id, t.table_name, (d.data->>'id') AS id, d.data
FROM jtables t
JOIN jdata d USING (table_id);

CREATE OR REPLACE FUNCTION public.vjdata_upsert() RETURNS trigger AS $$
BEGIN
  IF TG_OP = 'INSERT' THEN
    PERFORM public.jdata_insert(NEW.table_name, NEW.data);
  ELSE
    PERFORM public.jdata_update(NEW.table_name, NEW.id, NEW.data);
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER vjdata_upsert_trigger INSTEAD OF INSERT OR UPDATE
  ON public.vjdata FOR EACH ROW EXECUTE PROCEDURE public.vjdata_upsert();

UPDATE public.vjdata SET
  data = data || jsonb_build_object('quantity', (data->>'quantity')::int + 2)
WHERE table_name = 'product' AND id = '2'

SELECT * FROM public.vjdata WHERE table_name = 'product' AND id = '2';

顺便说一句,我不知道为什么会有人不喜欢存储的进程。与数据库交互的正确方式是通过视图和函数/进程。在过去15年中,使用纯代码的SQL是刚刚发生的事情,这仅仅是因为它的方便性和SQL技能的丧失。对大多数人来说,进行设置操作比使用pro更难cedural processing.

您可以使用
JSON(b)\u populate\u record
函数:
select(JSON\u populate\u record(null::product,('{“product”:{“name”:“product A”,“quantity”:100}}::JSON)->“product”)将JSON转换为行.*;
非常感谢,它很有魅力!我会将这个问题保留一段时间,以防有人愿意提交其他解决方案。但这个问题是可靠的!