AnchovyLegend AnchovyLegend - 17 hours ago 2
Javascript Question

MySQL with promises - losing value

In the code below, the goal is to populate the likes field for every post. I am querying the posts table and converting the posts to an object. Based on a value in this converted result set, I'm querying the likes table and am trying to add the corresponding likes result set to the posts object dynamically as shown below.

The likes field seems to be added successfully within the map function. However, due to some issue with handling the promises, the

likes
field does not exist outside the
then()
code block.

Any idea why this is? I appreciate any assistance on how to resolve this issue.

router.post('/load', (req, res) => {

connection.then( (conn) => {
return conn.query("SELECT userId, postId FROM posts");
}).then( (postsRows) => {

let posts = postsRows.map((r) => Object.assign({}, r));

posts.map( (post, i) => {
if( posts[i].totalLikes ) {
connection.then( (conn) => {
return conn.query("SELECT u.userId, u.first, u.last FROM likes l JOIN posts p ON p.postId = l.postId JOIN users u ON u.userId = l.userId WHERE p.postId = ?", [post.postId]);
}).then( (likesRows) => {
posts[i].likes = likesRows.map((r) => Object.assign({}, r));
});
}
});

return posts;

}).then( (posts) => {
console.log(posts);
});
});

Answer

Changes:

  1. Just chain the mapping together
  2. No need to use i for access when mapping because the item is already given as first argument
  3. Since you're mapping promises, you must use something like Promise.all to resolve them
  4. You already resolve connection.then, no need to do it again. You can reuse conn from the upper scope.
  5. Maybe you can also extract the object copying into a helper to clean things up further

Here's the code:

const copyObject = o => Object.assign({}, o));
connection.then(conn => 
  conn
    .query("SELECT userId, postId FROM posts")
    .then(postRows => Promise.all(
      postRows
        .map(copyObject)
        .map((post) => {
          const getLikes = post.totalLikes
            ? conn.query("SELECT u.userId, u.first, u.last FROM likes l JOIN posts p ON p.postId = l.postId JOIN users u ON u.userId = l.userId WHERE p.postId = ?", [post.postId])
            : Promise.resolve([]);
          return getLikes
            .then(likesRows => {
              post.likes = likesRows;
              return post;
            });
        })
    ))
)
.then(posts => {
  console.log(posts);
})