如何保存和 return JavaScript 带有归一化子数组的对象 SQL
How to save and return JavaScript Object with Subarray in Normalized SQL
我正在使用 postgres-node
,但我认为这对于拥有 javascript 对象且其子数组要保存在 SQL 中的任何人来说都是一个问题。我有一个 javascript 个具有不同数量(任意长度)特征数组的对象:
{
name: "Ted",
features: ['Red Hair', 'Blue Eyes']
}
所以当我有几个时,javascript 格式如下:
[
{
name: "Ted",
features: ['Red Hair', 'Blue Eyes']
},
{
name: "Ann",
features: ['Brown Hair', 'Blue Eyes', 'Big Smile']
}
]
太棒了!但是如何在规范化后从数据库中取回它呢?我已经在我的数据库中将其标准化,如下所示:
people
Table
+---+------------+
|id | Name |
+---+------------+
| 1 | Ted |
| 2 | Ann |
+---+------------+
features
table
+---+--------------+
|id | feature_name |
+---+--------------+
| 1 | Red Hair |
| 2 | Blue Eyes |
| 3 | Brown Hair |
| 4 | Big Smile |
+---+--------------+
与people_features
结table
+---+-----------+-------------+
|id | person_id | feature_id |
+---+-----------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 2 | 3 |
| 5 | 2 | 4 |
+---+-----------+-------------+
如果我这样连接:
SELECT name, feature_name
FROM people
JOIN people_features ON people_features.person_id=people.id
JOIN features ON people_features.feature_id=features.id;
我为每个人排了一排。这不是我想要的。
我得到的:
[
{
name: "Ted",
feature_name: 'Red Hair'
},
{
name: "Ted",
feature_name: 'Blue Eyes'
},
{
name: "Ann",
feature_name: 'Blue Eyes'
},
{
name: "Ann",
feature_name: 'Brown Hair'
},
{
name: "Ann",
feature_name: 'Big Smile'
}
]
我想要的:
[
{
name: "Ted",
features: ['Red Hair', 'Blue Eyes']
},
{
name: "Ann",
features: ['Brown Hair', 'Blue Eyes', 'Big Smile']
}
]
这看起来糟透了!现在我需要遍历这些并将相同的人组合成一个人对象。我的另一个选择似乎是为人民提出要求
SELECT id, name
FROM people;
哪个 return:
[
{
id: 1
name: "Ted"
},
{
id: 2
name: "Ann"
}
]
然后我需要循环并为每个人进行单独的 SQL 查询?
每个人:
SELECT feature_name
FROM features
JOIN people_features ON features.id=people_features.feature_id
WHERE people_features.person_id =
($1 是我正在循环的人的 ID)
然后我会回来(给泰德):
[
{ feature_name: 'Red Hair' },
{ feature_name: 'Blue Eyes' }
]
然后我需要从它们的对象中删除它们(只获取字符串),然后将它们添加到对象中。
其中一种是最好的方法吗?感觉他们两个都效率很低
应该这样做:
SELECT name, array_agg(feature_name)
FROM people
JOIN people_features ON people_features.person_id=people.id
JOIN features ON people_features.feature_id=features.id
GROUP BY people.id;
Vao Tsun 的回答很完美。对于那些感兴趣的人,这是我最终在我的节点代码中使用的最小版本,以使其与 node-postgres
:
一起工作
var pg = require('pg');
var config = {
user: process.env.PG_USER || null, //env var: PGUSER
password: process.env.DATABASE_SECRET || null, //env var: PGPASSWORD
host: process.env.DATABASE_SERVER || 'localhost', // Server hosting the postgres database
port: process.env.DATABASE_PORT || 5432, //env var: PGPORT
database: process.env.DATABASE_NAME || 'lukeschlangen', //env var: PGDATABASE
max: 10, // max number of clients in the pool
idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
};
var pool = new pg.Pool(config)
pool.connect(function (err, client, done) {
if (err) {
console.log('There was an error', err);
} else {
client.query(
'SELECT name, array_agg(feature_name) ' +
'FROM people ' +
'JOIN people_features ON people_features.person_id=people.id ' +
'JOIN features ON people_features.feature_id=features.id ' +
'GROUP BY people.id;',
function (err, results) {
done();
console.log(results.rows); // This was exactly the array I wanted
}
);
}
});
我正在使用 postgres-node
,但我认为这对于拥有 javascript 对象且其子数组要保存在 SQL 中的任何人来说都是一个问题。我有一个 javascript 个具有不同数量(任意长度)特征数组的对象:
{
name: "Ted",
features: ['Red Hair', 'Blue Eyes']
}
所以当我有几个时,javascript 格式如下:
[
{
name: "Ted",
features: ['Red Hair', 'Blue Eyes']
},
{
name: "Ann",
features: ['Brown Hair', 'Blue Eyes', 'Big Smile']
}
]
太棒了!但是如何在规范化后从数据库中取回它呢?我已经在我的数据库中将其标准化,如下所示:
people
Table
+---+------------+
|id | Name |
+---+------------+
| 1 | Ted |
| 2 | Ann |
+---+------------+
features
table
+---+--------------+
|id | feature_name |
+---+--------------+
| 1 | Red Hair |
| 2 | Blue Eyes |
| 3 | Brown Hair |
| 4 | Big Smile |
+---+--------------+
与people_features
结table
+---+-----------+-------------+
|id | person_id | feature_id |
+---+-----------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 2 | 3 |
| 5 | 2 | 4 |
+---+-----------+-------------+
如果我这样连接:
SELECT name, feature_name
FROM people
JOIN people_features ON people_features.person_id=people.id
JOIN features ON people_features.feature_id=features.id;
我为每个人排了一排。这不是我想要的。
我得到的:
[
{
name: "Ted",
feature_name: 'Red Hair'
},
{
name: "Ted",
feature_name: 'Blue Eyes'
},
{
name: "Ann",
feature_name: 'Blue Eyes'
},
{
name: "Ann",
feature_name: 'Brown Hair'
},
{
name: "Ann",
feature_name: 'Big Smile'
}
]
我想要的:
[
{
name: "Ted",
features: ['Red Hair', 'Blue Eyes']
},
{
name: "Ann",
features: ['Brown Hair', 'Blue Eyes', 'Big Smile']
}
]
这看起来糟透了!现在我需要遍历这些并将相同的人组合成一个人对象。我的另一个选择似乎是为人民提出要求
SELECT id, name
FROM people;
哪个 return:
[
{
id: 1
name: "Ted"
},
{
id: 2
name: "Ann"
}
]
然后我需要循环并为每个人进行单独的 SQL 查询?
每个人:
SELECT feature_name
FROM features
JOIN people_features ON features.id=people_features.feature_id
WHERE people_features.person_id =
($1 是我正在循环的人的 ID)
然后我会回来(给泰德):
[
{ feature_name: 'Red Hair' },
{ feature_name: 'Blue Eyes' }
]
然后我需要从它们的对象中删除它们(只获取字符串),然后将它们添加到对象中。
其中一种是最好的方法吗?感觉他们两个都效率很低
应该这样做:
SELECT name, array_agg(feature_name)
FROM people
JOIN people_features ON people_features.person_id=people.id
JOIN features ON people_features.feature_id=features.id
GROUP BY people.id;
Vao Tsun 的回答很完美。对于那些感兴趣的人,这是我最终在我的节点代码中使用的最小版本,以使其与 node-postgres
:
var pg = require('pg');
var config = {
user: process.env.PG_USER || null, //env var: PGUSER
password: process.env.DATABASE_SECRET || null, //env var: PGPASSWORD
host: process.env.DATABASE_SERVER || 'localhost', // Server hosting the postgres database
port: process.env.DATABASE_PORT || 5432, //env var: PGPORT
database: process.env.DATABASE_NAME || 'lukeschlangen', //env var: PGDATABASE
max: 10, // max number of clients in the pool
idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
};
var pool = new pg.Pool(config)
pool.connect(function (err, client, done) {
if (err) {
console.log('There was an error', err);
} else {
client.query(
'SELECT name, array_agg(feature_name) ' +
'FROM people ' +
'JOIN people_features ON people_features.person_id=people.id ' +
'JOIN features ON people_features.feature_id=features.id ' +
'GROUP BY people.id;',
function (err, results) {
done();
console.log(results.rows); // This was exactly the array I wanted
}
);
}
});