【问题标题】:Options to model JSON data in a Postgresql database?在 Postgresql 数据库中对 JSON 数据建模的选项?
【发布时间】:2023-02-15 02:09:52
【问题描述】:

我有一个 JSON 文件,其中包含有关员工及其技能的数据。我需要以某种方式在 PostgreSQL 数据库中对数据建模(原因与我们正在开发的应用程序有关)。

JSON 文件有很多我的应用程序并不真正需要的数据(至少现在是这样)。我只需要几列:员工 ID、姓名、资格。但是其余的数据应该存储在表中(只是暂时的,因为这仍然是一个 POC)。

数据



{
  "employee": {
  "ID": 654534543,,
  "Name": "Max Mustermann",
  "Email": "max.mustermann@firma.de",
  "skills": [
    {"name": python, "level": 3},
    {"name": c, "level": 2},
    {"name": openCV, "level": 3}
    ],
  },
"employee":{
  "ID": 3213213,,
  "Name": "Alex Mustermann",
  "Email": "alex.mustermann@firma.de",
  "skills":[
    {"name": Jira, "level": 3},
    {"name": Git, "level": 2},
    {"name": Tensorflow, "level": 3}
    ],
  }
};

我想创建一个包含以下列的表:员工 ID 作为主键,名称为 CHAR,技能为数组,JSONB 为员工的其余信息。

桌子

CREATE TABLE employee(
    id INT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(255) NOT NULL,
    description VARCHAR (255),
        skills TEXT [],
        join_date DATE,      

);

需要牢记的一些因素:数据应定期更新(比如每月一次),应用程序应使用数据库查询一个(或多个)涵盖特定所需技能(和技能水平)的员工 ID ).到目前为止,我们不确定是否要查询 json 字段(但在不久的将来可能会实现)

此外,数据复杂而密集(我在下面附加的只是一个简化的示例),所以我想直接从 JSONB 列查询不方便(如其他类似问题所述)

我现在的问题是: 1- 建议的数据模型是否满足所需条件,我们有一个巨大的 json 数据文件(快速搜索员工技能、可扩展、简单/快速查询和检索员工数据(例如员工 ID)?

2- 开发关系数据库模式时应该考虑什么?

3- 将数据拆分成多个表会有优势吗?例如一张以员工 ID 作为主键的员工个人数据表,一张以员工 ID 作为外键的技能表和一个技能文本字段,一个 JSON 表用于其余数据。

我在 Windows 10 上使用 PostgreSQL 15.1。我还在熟悉 PostgreSQL 数据库。

非常感谢

【问题讨论】:

    标签: json postgresql


    【解决方案1】:

    这是我会做的:

    create table employee (
      id bigint not null primary key,
      name text not null,
      email text not null
    );
    
    create table skill (
      id bigint generated always as identity primary key,
      skill_name text not null unique
    );
    
    create table employee_skill (
      id bigint generated always as identity primary key,
      employee_id bigint not null references employee(id),
      skill_id bigint not null references skill(id),
      skill_level int not null,
      unique (employee_id, skill_id)
    );
    
    

    然后,填充模式(在使用 JSON 更正错误之后):

    with indata as (
      select '[
      {
      "ID": 654534543,
      "Name": "Max Mustermann",
      "Email": "max.mustermann@firma.de",
      "skills": [
        {"name": "python", "level": 3},
        {"name": "c", "level": 2},
        {"name": "openCV", "level": 3}
        ]
      },
      {
      "ID": 3213213,
      "Name": "Alex Mustermann",
      "Email": "alex.mustermann@firma.de",
      "skills":[
        {"name": "Jira", "level": 3},
        {"name": "Git", "level": 2},
        {"name": "Tensorflow", "level": 3}
        ]
      }
    ]'::jsonb as j
    ), expand as (
      select emp, skill
        from indata
             cross join lateral jsonb_array_elements(j) as el(emp)
             cross join lateral jsonb_array_elements(emp->'skills') as sk(skill)
    ), insemp as (
      insert into employee (id, name, email)
      select distinct (emp->>'ID')::bigint, emp->>'Name', emp->>'Email'
        from expand
      on conflict (id) do update
        set name = excluded.name, email = excluded.email
      returning *
    ), insskill as (
      insert into skill (skill_name)
      select distinct skill->>'name'
        from expand
      on conflict (skill_name) do nothing
      returning *
    ), allemp as (
      select * from insemp union select * from employee
    ), allskill as (
      select * from insskill union select * from insskill
    ), insempskill as (
      insert into employee_skill (employee_id, skill_id, skill_level)
      select e.id as employee_id, s.id as skill_id, 
             (i.skill->>'level')::int as skill_level
        from expand i
             join allemp e on e.id = (i.emp->>'ID')::bigint
             join allskill s on s.skill_name = i.skill->>'name'
      on conflict (employee_id, skill_id) do update
        set skill_level = excluded.skill_level
      returning *
    )
    delete from employee_skill
     where (employee_id, skill_id) not in 
      (select employee_id, skill_id from insempskill 
        union 
       select employee_id, skill_id from employee_skill)
    ;
    

    working fiddle

    【讨论】:

      猜你喜欢
      • 2015-12-18
      • 2011-09-24
      • 1970-01-01
      • 2011-08-09
      • 2015-10-28
      • 1970-01-01
      • 2017-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多