knex js查询多对多
knex js query many to many
我在使用节点时遇到问题 & knex.js
我正在尝试构建一个带有 post 的迷你博客,并添加了向 post
添加多个标签的功能
我有一个 POST 模型 具有以下属性:
id SERIAL PRIMARY KEY NOT NULL,
name TEXT,
其次,我有 标签模型 用于存储标签:
id SERIAL PRIMARY KEY NOT NULL,
name TEXT
我有很多 table:Post 标签 引用了 post 和标签:
id SERIAL PRIMARY KEY NOT NULL,
post_id INTEGER NOT NULL REFERENCES posts ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES tags ON DELETE CASCADE
我成功插入了标签,并创建了 post 标签,
但是当我想获取 Post 带有附加标签的数据时 post 我遇到了麻烦
这里有个问题:
const data = await knex.select('posts.name as postName', 'tags.name as tagName'
.from('posts')
.leftJoin('post_tags', 'posts.id', 'post_tags.post_id')
.leftJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
以下查询 returns 这个结果:
[
{
postName: 'Post 1',
tagName: 'Youtube',
},
{
postName: 'Post 1',
tagName: 'Funny',
}
]
但我希望结果的格式和返回方式如下:
{
postName: 'Post 1',
tagName: ['Youtube', 'Funny'],
}
这甚至可以通过查询实现,还是我必须手动格式化数据?
结果是正确的,因为这就是 SQL 的工作方式 - 它 returns 行数据。 SQL 除了 table(想想 CSV 数据或 Excel 电子表格)没有返回任何东西的概念。
您可以使用 SQL 做一些有趣的事情,这些事情可以将标签转换为您连接在一起的字符串,但这并不是您真正想要的。无论哪种方式,您都需要添加 post 处理步骤。
对于您当前的查询,您可以简单地执行如下操作:
function formatter (result) {
let set = {};
result.forEach(row => {
if (set[row.postName] === undefined) {
set[row.postName] = row;
set[row.postName].tagName = [set[row.postName].tagName];
}
else {
set[row.postName].tagName.push(row.tagName);
}
});
return Object.values(set);
}
// ...
query.then(formatter);
这应该不会很慢,因为您只循环一次结果。
实现此目的的一种方法是使用某种聚合函数。如果您使用的是 PostgreSQL:
const data = await knex.select('posts.name as postName', knex.raw('ARRAY_AGG (tags.name) tags'))
.from('posts')
.innerJoin('post_tags', 'posts.id', 'post_tags.post_id')
.innerJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
.groupBy("postName")
.orderBy("postName")
.first();
->
{ postName: 'post1', tags: [ 'tag1', 'tag2', 'tag3' ] }
对于MySQL:
const data = await knex.select('posts.name as postName', knex.raw('GROUP_CONCAT (tags.name) as tags'))
.from('posts')
.innerJoin('post_tags', 'posts.id', 'post_tags.post_id')
.innerJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
.groupBy("postName")
.orderBy("postName")
.first()
.then(res => Object.assign(res, { tags: res.tags.split(',')}))
MySQL中没有数组,GROUP_CONCAT只会将所有标签拼接成一个字符串,所以我们需要手动拆分。
->
RowDataPacket { postName: 'post1', tags: [ 'tag1', 'tag2', 'tag3' ] }
我在使用节点时遇到问题 & knex.js
我正在尝试构建一个带有 post 的迷你博客,并添加了向 post
添加多个标签的功能我有一个 POST 模型 具有以下属性:
id SERIAL PRIMARY KEY NOT NULL,
name TEXT,
其次,我有 标签模型 用于存储标签:
id SERIAL PRIMARY KEY NOT NULL,
name TEXT
我有很多 table:Post 标签 引用了 post 和标签:
id SERIAL PRIMARY KEY NOT NULL,
post_id INTEGER NOT NULL REFERENCES posts ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES tags ON DELETE CASCADE
我成功插入了标签,并创建了 post 标签, 但是当我想获取 Post 带有附加标签的数据时 post 我遇到了麻烦
这里有个问题:
const data = await knex.select('posts.name as postName', 'tags.name as tagName'
.from('posts')
.leftJoin('post_tags', 'posts.id', 'post_tags.post_id')
.leftJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
以下查询 returns 这个结果:
[
{
postName: 'Post 1',
tagName: 'Youtube',
},
{
postName: 'Post 1',
tagName: 'Funny',
}
]
但我希望结果的格式和返回方式如下:
{
postName: 'Post 1',
tagName: ['Youtube', 'Funny'],
}
这甚至可以通过查询实现,还是我必须手动格式化数据?
结果是正确的,因为这就是 SQL 的工作方式 - 它 returns 行数据。 SQL 除了 table(想想 CSV 数据或 Excel 电子表格)没有返回任何东西的概念。
您可以使用 SQL 做一些有趣的事情,这些事情可以将标签转换为您连接在一起的字符串,但这并不是您真正想要的。无论哪种方式,您都需要添加 post 处理步骤。
对于您当前的查询,您可以简单地执行如下操作:
function formatter (result) {
let set = {};
result.forEach(row => {
if (set[row.postName] === undefined) {
set[row.postName] = row;
set[row.postName].tagName = [set[row.postName].tagName];
}
else {
set[row.postName].tagName.push(row.tagName);
}
});
return Object.values(set);
}
// ...
query.then(formatter);
这应该不会很慢,因为您只循环一次结果。
实现此目的的一种方法是使用某种聚合函数。如果您使用的是 PostgreSQL:
const data = await knex.select('posts.name as postName', knex.raw('ARRAY_AGG (tags.name) tags'))
.from('posts')
.innerJoin('post_tags', 'posts.id', 'post_tags.post_id')
.innerJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
.groupBy("postName")
.orderBy("postName")
.first();
->
{ postName: 'post1', tags: [ 'tag1', 'tag2', 'tag3' ] }
对于MySQL:
const data = await knex.select('posts.name as postName', knex.raw('GROUP_CONCAT (tags.name) as tags'))
.from('posts')
.innerJoin('post_tags', 'posts.id', 'post_tags.post_id')
.innerJoin('tags', 'tags.id', 'post_tags.tag_id')
.where('posts.id', id)
.groupBy("postName")
.orderBy("postName")
.first()
.then(res => Object.assign(res, { tags: res.tags.split(',')}))
MySQL中没有数组,GROUP_CONCAT只会将所有标签拼接成一个字符串,所以我们需要手动拆分。
->
RowDataPacket { postName: 'post1', tags: [ 'tag1', 'tag2', 'tag3' ] }