node的mysql一个问题,关于数据绑定问题
发布于 9 年前 作者 hinson0 4555 次浏览 最后一次编辑是 8 年前 来自 问答

表 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 回复

在线等

使用left join即可

@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){ })这样子嵌套一下去做。

对了,callback最好一层层往下传,尽量不要闭包用。。。

用sql关联 left join 然后将结果稍微改成前端需要的格式即可

异步的函数返回的数据需要聚合,去看看 eventproxy 这个库

你这种数据格式本来用mongo最合适,不过mysql也可以办到,就是写两个查询,msyql属性可以设置multipleStatements: true, 代表可以执行两个查询语句,之所以这样是因为left join也无法得到这种带数组的数据结构,至少我还不知道,所以你可以拿到查询的结果rows[0],rows[1],然后拼接为这种数据结构

async欢迎你

Promise.All 貌似可以

在查询callback中递归调用

db.query(query, function(err, rows) {
  if(!err) {
    index++;
	//递归调用
  }
});

简单到一了,这种查询不要请求太多,任何一次额外的请求响应都是增加延迟。

[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);
		})
	});
}
  1. nodejs新手,但上述代码貌似有逻辑错误。手机上的,用PHP代码演示下。
  2. $res=…//SQL查询结果
  3. foreach($res as $k =<> $v){ $v[“aaa”]=123;//这样的赋值方式,不能影响$res. } post.comments=comments;cu错误。 改喂为,posts.comments=comments;

万恶的输入框,删除不掉。。 f $er

感觉4楼也对,看来异步改变不止是体验,还有代码执行顺序问题啊。如此,所,此处return,需要基,事件驱动? 万恶的输入框,真删除不掉啊。。。

回到顶部