postgresql - 如何从 postgres jsonb 列中选择特定对象
问题描述
我将学生的评估存储在 jsonb 列调用评估中,数据库中的每一行都存储学生对特定学科的评估,并且我试图获取有助于检索的查询: 1. 特定学生的评估主题。2. 学生提供的每门学科的所有学生评估。
这是我从表中选择所有记录时得到的结果。
[
{
"id": "22670f29-1437-4af1-b907-f6940377a851",
"sessionId": 3,
"sectionId": 4,
"subjectId": 8,
"assessment": [
{
"exam": 50,
"grdae": "A",
"total": 79,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
},
{
"exam": 50,
"grdae": "B",
"total": 69,
"position": "Third",
"student_id": 3,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Elvis"
}
]
},
{
"id": "beca9d97-0d0a-4d89-b8c5-c9a6fed812a5",
"sessionId": 3,
"sectionId": 4,
"subjectId": 10,
"assessment": [
{
"exam": 50,
"grdae": "A",
"total": 79,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
},
{
"exam": 50,
"grdae": "B",
"total": 69,
"position": "Third",
"student_id": 3,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Elvis"
}
]
},
{
"id": "1ed9c3d6-2482-4b1d-ab59-b77a8933699c",
"sessionId": 3,
"sectionId": 4,
"subjectId": 9,
"assessment": [
{
"exam": 50,
"grdae": "A",
"total": 90,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
},
{
"exam": 50,
"grdae": "B",
"total": 69,
"position": "Third",
"student_id": 3,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Elvis"
}
]
}
]
此结果包含对不同科目的评估,其中两个学生的科目 ID 分别为 8、9 和 10,ID 为 2 和 3。
注意:sessionID
和SectionID
也是subjectId
表调用评估中的列。
如果我想要一个 id 为 2 的学生评估的 subjectId 为 9 且 sessionId 为 3 并且 sectionId 为 4,我应该能够得到这个对象作为回报:
{
"exam": 50,
"grdae": "A",
"total": 90,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
}
如果我想要一个对所有三个 subjectId 进行 id 2 评估的学生,即 id 8、9、10,并且 sessionId 为 3,sectionId 为 4,我应该得到这个结果:
[
{
"exam": 50,
"grdae": "A",
"total": 90,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
},
{
"exam": 50,
"grdae": "A",
"total": 79,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
},
{
"exam": 50,
"grdae": "A",
"total": 79,
"position": "First",
"student_id": 2,
"assessment_1": 9,
"assessment_2": 17,
"assessment_4": 5,
"student_name": "Anana Aristotle"
}
]
解决方案
将小提琴中的数据最小化为:
[
{
"sessionId": 3,
"sectionId": 4,
"subjectId": 8,
"assessment": [
{
"student_id": 2
},
{
"student_id": 3
}
]
},
{
"sessionId": 3,
"sectionId": 4,
"subjectId": 10,
"assessment": [
{
"student_id": 2
},
{
"student_id": 3
}
]
},
{
"sessionId": 3,
"sectionId": 4,
"subjectId": 9,
"assessment": [
{
"student_id": 2
},
{
"student_id": 3
}
]
}
]
第一步是取消嵌套相关的 id 信息:
SELECT
assessments,
(elems ->> 'sessionId')::int as session_id,
(elems ->> 'sectionId')::int as section_id,
(elems ->> 'subjectId')::int as subject_id,
(assessments ->> 'student_id')::int AS student_id
FROM
mytable,
json_array_elements(jsondata) as elems,
json_array_elements(elems -> 'assessment') as assessments
这导致:
assessments | session_id | section_id | subject_id | student_id
:--------------- | ---------: | ---------: | ---------: | ---------:
{"student_id":2} | 3 | 4 | 8 | 2
{"student_id":3} | 3 | 4 | 8 | 3
{"student_id":2} | 3 | 4 | 10 | 2
{"student_id":3} | 3 | 4 | 10 | 3
{"student_id":2} | 3 | 4 | 9 | 2
{"student_id":3} | 3 | 4 | 9 | 3
该json_array_elements()
函数将 json 数组嵌套到每个数组元素的一条记录中。因为有两个嵌套数组,所以需要调用这个函数两次。您可以在SELECT
列表中看到每个级别的值。
之后,您可以在WHERE
子句中过滤您想要的任何内容。结果记录(相关评估对象)可以使用json_agg()
聚合函数进行分组:
SELECT
json_agg(assessments)
FROM (
-- query from above
) s
WHERE session_id IN (3)
AND section_id IN (4)
AND subject_id IN (9) -- only one subject
AND student_id IN (2)
或者
SELECT
json_agg(assessments)
FROM (
-- query from above
) s
WHERE session_id IN (3)
AND section_id IN (4)
AND subject_id IN (8,9,10) -- more subjects
AND student_id IN (2)
推荐阅读
- docker - kubelet 无法在 Ubuntu 上启动:配置错误:kubelet cgroup driver:\"systemd\" is different from docker cgroup driver:\"cgroupfs\"
- javascript - 我无法将设备状态发送给 Alexa
- mongodb - 如何使用 mongodump & mongorestore 在 Dockerfile 中自动导入数据库?
- reactjs - 在什么场景下,react生命周期钩子是必须的
- dictionary - 使用 deepmerge python 模块和使用 ruamel.yaml 合并 2 个 yaml 时保留注释的问题
- matlab - 使用 SSD ResNet50 进行迁移学习中的 MATLAB Nan 问题(验证损失和小批量损失)
- wordpress - Wordpress rest api 请求返回 rest_cookie_invalid_nonce
- arrays - 将 jq unique_by 与数组一起使用
- javascript - 为什么我得到一个圆形对象数组?
- r - 使用 ggplot 为数据集中的所有列与单个因变量创建箱线图