多维数组输出为JSON

时间:2016-05-28 18:36:17

标签: sql postgresql

我想做一些我不太确定的事情。

我从类似的数据库开始:

create table events (id int primary key, common int, location text);

insert into events values (2, 100, 'Something');
insert into events values (3, 100, 'Something');
insert into events values (4, 100, 'Something');
insert into events values (5, 200, 'Something');
insert into events values (6, 200, 'Something');
insert into events values (7, 200, 'Something');
insert into events values (8, 200, 'Something');
insert into events values (9, 100, 'Something');
insert into events values (10, 200, 'Something');
insert into events values (11, 200, 'Something');
insert into events values (12, 200, 'Something');
insert into events values (13, 300, 'Something');
insert into events values (14, 200, 'Something');
insert into events values (15, 300, 'Something');
insert into events values (16, 200, 'Something');
insert into events values (17, 300, 'Something');

我希望将数据分组为一个对象,其中common值为键:

{
  "100":{
    "2":"Something",
    "3":"Something",
    "4":"Something",
    "9":"Something"},
  "200":{
    "5":"Something",
    "6":"Something",
    "7":"Something",
    "8":"Something"},
  "300":{
    "13":"Something",
    "15":"Something",
    "17":"Something",
    "18":"Something"}
}

当然,我可以通过多次选择来做到这一点,但单个选择将是有益的。

任何帮助都会很棒!谢谢!

1 个答案:

答案 0 :(得分:2)

适用于任何版本的PostgreSQL

这里的重要部分是正确的SELECT,它可以将数据分组,以便轻松转换为字典类型:

SELECT * FROM events GROUP BY common, id ORDER BY common

它产生以下输出:

2    100    "Something"
3    100    "Something"
4    100    "Something"
9    100    "Something"
5    200    "Something"
6    200    "Something"
7    200    "Something"
8    200    "Something"
10   200    "Something"
11   200    "Something"
12   200    "Something"
14   200    "Something"
16   200    "Something"
13   300    "Something"
15   300    "Something"
17   300    "Something"

此时,无论您使用哪种语言作为服务器端代码,将其转换为使用common作为键的字典都变得很容易。

例如,在Node.js中你可以这样做:

function transform(rows) {
    var key, obj, result = {};
    rows.forEach(function (r) {
        if (r.common !== key) {
            if (obj) {
                result[key] = obj;
            }
            obj = {};
            key = r.common;
        }
        obj[r.id] = r.location;
    });
    if (obj) {
        result[key] = obj;
    }
    return result;
}

有关完整示例,请使用pg-promise

db.query('SELECT * FROM events GROUP BY common, id ORDER BY common')
    .then(data=> {
        console.log(transform(data));
    })
    .catch(error=> {
        console.log(error);
    });

输出:

{
    '100': {
        '2': 'Something',
        '3': 'Something',
        '4': 'Something',
        '9': 'Something'
    },
    '200': {
        '5': 'Something',
        '6': 'Something',
        '7': 'Something',
        '8': 'Something',
        '10': 'Something',
        '11': 'Something',
        '12': 'Something',
        '14': 'Something',
        '16': 'Something'
    },
    '300': {
        '13': 'Something',
        '15': 'Something',
        '17': 'Something'
    }
}

对于PostgreSQL 9.4及更高版本

使用PostgreSQL 9.4及更高版本,您可以使用函数json_object_agg在SQL中完成所有操作:

SELECT json_object_agg(common, j ORDER BY common)
FROM (SELECT common, json_object_agg(id, location order by id)
AS j FROM events GROUP BY common) t;

效果比较

比较标准与新方法的表现并不容易,但请考虑一下:

我们有一个简单的单选+非常简单快速的转换,而不是服务器上的双选+双聚合。因此,如果旧的解决方案胜过新的解决方案,我不会感到惊讶。