表 post id content user_id
表 comment id content post_id
前端工程师想要的数据格式:
[
{
"id": "帖子id,整型",
"content": "帖子内容,字符串",
"comments": [
{
"id": "评论ID,整型",
"content": "评论内容,整型",
"post_id": "所属帖子ID,整型",
},
...
]
}
]
node的代码我是这么写的:假设去用户ID=1的帖子
// 上面省略代码...
function Post() {
}
// 获取帖子
Post.getListByUserId = function(userId, callback) {
var query = db.query('SELECT * FROM post WHERE user_id = ?', userId, function(err, posts) {
// 出错
if (err) {
console.log(err);
return;
}
// 遍历帖子 -> 下面的代码是有问题的代码,第一次用Node,按照PHP那种同步的思想来做了,不知道怎么得到前端工程师想要的这样的数据结构????
// 问题1:db.query 是异步的,所以我不知道如何收集结果集
posts.forEach(function(post) {
db.query('SELECT * FROM comment WHERE post_id = ?', post.id, function(err, comments) {
post.comments = comments;
});
});
return callback(posts);
});
}
14 回复
@i5ting left join的数据结构是平行的。
db.query('SELECT post.*, comment.content AS comment_content, comment.id AS comment_id FROM post INNER JOIN comment ON post.id = comment.post_id WHERE user_id = ?', ...);
你有没有打印出来看一看啊。你这么写没什么问题。唯一我觉得有点毛病的是db.query是异步的,post.comments = comments;还没执行就已经return callback(posts);了。。你先打印一下看看你的结果。如果posts部分是空,function(err, comments,callback(posts){ })这样子嵌套一下去做。
你这种数据格式本来用mongo最合适,不过mysql也可以办到,就是写两个查询,msyql属性可以设置multipleStatements: true, 代表可以执行两个查询语句,之所以这样是因为left join也无法得到这种带数组的数据结构,至少我还不知道,所以你可以拿到查询的结果rows[0],rows[1],然后拼接为这种数据结构
简单到一了,这种查询不要请求太多,任何一次额外的请求响应都是增加延迟。
[1.] 如果请求的数据量不是超级大(客观上允许响应数据冗余),可以放在一个查询,然后把结果做一次手工聚合
var query = `
select
post.id as id,
post.content as content,
comment.id as comment_id,
comment.content as comment_content,
comment.post_id as comment_post_id
from post
left join comment on post.id = comment.post_id
where post.user_id = ?;
`;
function getListByUserId(userId, callback) {
function walk(rows) {
var indexes = {};
var sets = [];
var push_comment = function (stack, row) {
if (typeof row.comment_id === 'number')
stack.push({
id : row.comment_id,
content : row.comment_content,
post_id : row.comment_post_id
});
};
var item;
rows.forEach(function (row) {
if (row.id in indexes)
push_comment(sets[indexes[row.id]].comments, row);
else {
item = {id:row.id, content:row.content, comments:[]};
push_comment(item.comments, row);
indexes[row.id] = sets.length ;
sets.push(item);
}
});
return sets;
}
db.query(query, [userId], function (err, replies) {
if (err)
callback(err, null);
else
callback(null, walk(replies));
})
}
[2.] 如果数据很大,应该也只分成两个查询,再回来聚合
var mysql = require('mysql');
var query_post = 'select id, content from post where user_id = ?;';
var query_comment = 'select id, content from comment where post_id = ?;';
function getListByUserId(userId, callback) {
db.query(query_post, [userId], function (err, replies) {
if (err) return callback(err, null);
var query_comments = replies.map(function (reply) {
return mysql.format(query_comment, reply.id);
}).join('\n');
db.query(query_comments, function (err, _replies) {
if (err) return callback(err, null);
for (var i = 0, len = _replies.length; i < len; i++)
replies[i].comments = _replies[i].length > 0 ? _replies[i] : [];
callback(null, replies);
})
});
}