javascript - 在 Javascript 中从 PostgreSQL 查询结果中过滤掉唯一数据

标签 javascript postgresql

我有一个 PostgreSQL 数据库,我使用 node.jspg 模块从中查询数据。我的 Javascript 代码(在服务器端)中的结果数组包含大量重复值,因为这就是返回数据的方式。我相信查询没问题,因此值是重复的,因为多个 INNER JOINS 的表彼此独立,因此 A 的结果B 来自一个表(本例中为 qa_layers),结果为 CD 来自另一表(qa_cases 在本例中),以及来自第三个表的公共(public)值 E (在本例中为 qa_settings)将表示为

| settings_name | layer_name | case_name |
| E             | A          | C         |
| E             | A          | D         |
| E             | B          | C         |
| E             | B          | D         |

据我所知,这应该是预期的行为。我需要做的是将每列的唯一数据过滤为具有唯一值的数组,例如[A, B][C, D] 用于 layer_namecase_name。在我看来,可能有多种方法可以实现这一目标,但每种方法似乎都有点痛苦,除非有一些我不知道的帮助程序库或功能。

  1. 用 Javascript 解析数据库中的结果数组。由于存在多个 for 循环,这看起来很痛苦,但如果有一些库可以满足我的需要,这可能会很容易。
  2. 增强 PostgreSQL 查询,以便不需要或更少的解析。我不知道这是否可行,但如果生成的数组中有更容易解析的对象,则解析可能会不那么痛苦。我的查询粘贴在最后。
  3. 对数据库执行多次查询以获得正确的数据。对我来说,这似乎是可扩展性最差的解决方案,并且解析数组而不是运行多个连续查询时的开销会少很多。

我的 PostgreSQL 查询:

SELECT run.id, settings.name AS settings_name, layer.name AS layer_name, qa_case.name AS case_name FROM qa_runs AS run
    INNER JOIN qa_composites_in_run AS cr
        ON cr.run_id = run.id
    INNER JOIN qa_layers_in_composite AS lc
        ON lc.composite_name = cr.composite_name
    INNER JOIN qa_layers AS layer
        ON layer.name = lc.layer_name
    INNER JOIN qa_cases_in_run AS case_run
        ON case_run.run_id = run.id
    INNER JOIN qa_cases AS qa_case
        ON qa_case.name = case_run.case_name
    INNER JOIN qa_settings AS settings
        ON settings.name = run.settings_name
WHERE run.id IN (27,28,29);

我实际生成的 Javascript 数组:

[
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitLondon"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitRotterdam"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "wtf"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitLondon"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitRotterdam"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "wtf"
    },
    {
        "id": 28,
        "settings_name": "QA Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitLondon"
    },
    {
        "id": 28,
        "settings_name": "QA Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "wtf"
    },
    {
        "id": 27,
        "settings_name": "QA Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitLondon"
    },
    {
        "id": 27,
        "settings_name": "QA Default",
        "layer_name": "OpenStreetMapService",
        "case_name": "VisitRotterdam"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "Map2D",
        "case_name": "VisitLondon"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "Map2D",
        "case_name": "VisitRotterdam"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "Map2D",
        "case_name": "wtf"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "Map2D",
        "case_name": "VisitLondon"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "Map2D",
        "case_name": "VisitRotterdam"
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_name": "Map2D",
        "case_name": "wtf"
    },
    {
        "id": 28,
        "settings_name": "QA Default",
        "layer_name": "Map2D",
        "case_name": "VisitLondon"
    },
    {
        "id": 28,
        "settings_name": "QA Default",
        "layer_name": "Map2D",
        "case_name": "wtf"
    },
    {
        "id": 27,
        "settings_name": "QA Default",
        "layer_name": "Map2D",
        "case_name": "VisitLondon"
    },
    {
        "id": 27,
        "settings_name": "QA Default",
        "layer_name": "Map2D",
        "case_name": "VisitRotterdam"
    }
]

我希望数组/JSON最终如何:

[
    {
        "id": 27,
        "settings_name": "QA Default",
        "layer_names": [
            {
                "layer_name": "OpenStreetMapService"
            },
            {
                "layer_name": "Map2D"
            }
        ],
        "case_names": [
            {
                "case_name": "VisitLondon"
            },
            {
                "case_name": "VisitRotterdam"
            }
        ]
    },
    {
        "id": 28,
        "settings_name": "QA Default",
        "layer_names": [
            {
                "layer_name": "OpenStreetMapService"
            },
            {
                "layer_name": "Map2D"
            }
        ],
        "case_names": [
            {
                "case_name": "VisitLondon"
            },
            {
                "case_name": "wtf"
            }
        ]
    },
    {
        "id": 29,
        "settings_name": "Test Default",
        "layer_names": [
            {
                "layer_name": "OpenStreetMapService"
            },
            {
                "layer_name": "Map2D"
            }
        ],
        "case_names": [
            {
                "case_name": "VisitLondon"
            },
            {
                "case_name": "VisitRotterdam"
            },
            {
                "case_name": "wtf"
            }
        ]
    }
]

最佳答案

我建议在 PostgreSQL 端执行此操作,通过使用嵌套数据构造并返回一个 json 对象,而不是返回联接关系。

借助 9.3 及更高版本中的 json 支持,您可以相当轻松地完成此操作。如果没有示例数据和架构,我无法真正为您转换查询,但您需要从 json_aggrow_to_json 开始。查看其他相关问题,其答案也引用了这些函数。

这是一个简单的例子:

CREATE TABLE parent(
    id integer primary key,
    parentdata text
);

CREATE TABLE child(
    id integer primary key,
    parent_id integer not null references parent(id),
    childdata text
);

INSERT INTO parent(id, parentdata) VALUES 
(1, 'p1'), (2, 'p2'), (3, 'p3');

INSERT INTO child(id, parent_id, childdata)
VALUES
(10, 1, 'c1_10'),
(20, 2, 'c2_20'),
(21, 2, 'c2_21');

SELECT row_to_json(toplevel, true)
FROM (
  SELECT p.id, p.parentdata, json_agg(c) AS children 
  FROM parent p 
  LEFT OUTER JOIN child c ON (p.id = c.parent_id) GROUP BY p.id
) toplevel;

它发出:

{"id":1,
 "parentdata":"p1",
 "child":[{"id":10,"parent_id":1,"childdata":"c1_10"}]}
{"id":2,
 "parentdata":"p2",
 "child":[{"id":20,"parent_id":2,"childdata":"c2_20"}, 
 {"id":21,"parent_id":2,"childdata":"c2_21"}]}
{"id":3,
 "parentdata":"p3",
 "children":[null]}

如果您必须消除重复,您可能需要确保 SQL 中的 ORDER BY 子句已完全指定,以便行从外到内排序。目的。然后,您可以在 js 中线性扫描表并忽略对象 id 与前一行中同一实体的 id 相同的行。这是一个非常简单的单个 for 循环,带有一些状态跟踪变量。缺点是 PostgreSQL 必须对结果集进行排序。

关于javascript - 在 Javascript 中从 PostgreSQL 查询结果中过滤掉唯一数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30618181/

相关文章:

javascript - 如何在一张图片中找到另一张图片? Node .js

javascript - 如何从文件读取器返回调整大小的图像

postgresql - 迁移到 PostgreSQL 后无法访问 Liferay 中的任何帐户

postgresql - 如何配置 gitlab 以使用现有的 postgres 服务器

javascript - 如何使用 Redux connect 装饰器制作通用的 React 组件?

javascript - 将 JSON 编码为 Backbone.Model.save 的 URL 参数(patch = true)

sql - 在不存在的行上有 "select for update" block

sql - 复杂的 'Gaps and Islands' 问题

mysql - 如何将精度和比例部分包含在 liquibase 中的小数列定义中?

javascript - Gulp:在单个文件更改时运行 jshint