如果密钥已经存在,则以增量方式插入/更新嵌套的jsonb

时间:2020-10-13 10:00:03

标签: sql postgresql jsonb postgresql-11

我正在尝试在postgresql中创建一些API端点的日常使用日志。

我想将数据保留在嵌套的jsonb列中,以保持数据紧凑,因为我每天都不需要它。

模式如下:

CREATE TABLE clients (
  id INT,
  name TEXT,
  CONSTRAINT clients_pkey PRIMARY KEY (id)
);
INSERT INTO clients (id,name) VALUES (1,'John');
INSERT INTO clients (id,name) VALUES (2,'Mike');

CREATE TABLE client_usages (
  id INT,
  date DATE,
  usage_data JSONB,
  client_id INT,
  CONSTRAINT client_id_fk FOREIGN KEY (client_id)
        REFERENCES clients (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
);

CREATE UNIQUE INDEX clint_id_date_idx
    ON client_usages USING btree
    (client_id, date);

我需要存储的数据具有client_usage.usage_data中这样的嵌套结构:

{
  controller_name: {
    action_name: {
      status_code: 1
    }
  }
}

因此,对于每个请求,我都有controller_nameaction_namestatus_code的值。

我想创建一个通用的SQL调用,该调用将:

  1. 如果client_iddate的组合中不存在该记录,请插入该记录
  2. 如果记录已存在,则插入嵌套结构(如果尚未存在),计数器为1,如果存在,则将计数器增加1

例如,流程可能是:

控制器名称:"SomeController",操作名称:"some_action",状态代码:"200"

这应该导致插入JSONB结构,如:

{
  "SomeController": {
    "some_action": {
      "200": 1
    }
  }
}

现在让我们提出另一个请求:ontroller_name:"SomeController"和action_name: "some_acion"和status_code:"200",它应该只将1增至2,结果是:

{
  "SomeController": {
    "some_action": {
      "200": 2
    }
  }
}

如果随后出现另一个请求,例如controller_name:"SomeController",action_name:"some_action",status_code:"400",则它会导致:

{
  "SomeController": {
    "some_action": {
      "200": 2,
      "400": 1
    }
  }
}

然后出现另一个要求,例如controller_name:"AnotherController",action_name:"some_action",status_code:"400",那么它应导致:

{
  "SomeController": {
    "some_action": {
      "200": 2,
      "400": 1
    }
  },
  "AnotherController": {
    "some_action": {
      "400": 1
    }
  }
}

最后是"AnotherController",action_name:"new_action",status_code:"200",则结果应为:

{
  "SomeController": {
    "some_action": {
      "200": 2,
      "400": 1
    }
  },
  "AnotherController": {
    "some_action": {
      "400": 1
    },
    "new_action": {
      "200": 1
    }
  }
}

我认为这涵盖了所有情况

我正在考虑创建通用的INSERT语句和ON CONFLICT的{​​{1}},然后是(client_id, date)UPDATE的嵌套json。像这样:

usage_date

我的主要问题是,我无法弄清楚如何进行更新,要么创建丢失的密钥,要么将现有的密钥增加INSERT INTO client_usages (client_id, date, usage_data) VALUES(client_id, date, '{controller_name: {action_name: {status_code: 1}}}'::jsonb) /* where the variables of cause are replaced with real data... */ ON CONFLICT (client_id, date) DO UPDATE SET usage_data = /* this is where it get's harder.... */

我在这里创建了一个小提琴:https://www.db-fiddle.com/f/476bywubxAX2x7oGNtD3cK/1

0 个答案:

没有答案