0

I'm doing a clone of Twitter using PostgreSQL. The users can write posts and they can share them. There is a timeline for each user, where it shows the posts and the shares of the people he follows. I also have to show the difference between a shared post (retweet) and a regular one by the original author. I have the following problem when joining the tables:

Post                                                            
post_id | user_id | text                                        
1         1         text                                        

Shares                                                          
post_id | user_id                                               
1         2                                                     

Join_result                                                     
Post.post_id | Post.user_id | Post.text | Shares.post_id | Shares.user_id                                                           
1              1              text        1                2    

Then I filter by Post.user_id or Shares.user_id. However, with this result, I don't know if I'm showing the post because it is a user 2 sharing or user 1 post. A good solution to me, it would be this join table:

Join_result                                                     
Post.post_id | Post.user_id | Post.text | Shares.post_id | Shares.user_id                                                           
1              1              text        null             null 
1              1              text        1                2

Now I could filter correctly:

(Post.user_id in following and Share.user_id is NULL) or Share.user_id in followings

In this example, if the user follows user 1, it returns the first row; if he follows user 2 I get the second one and if he follows the two users, returns the two rows.

I've already solved this problem using a UNION query but I'd like to know if there is another solution (and better).

EDIT the query:

SELECT p0* f1.*, FROM "posts" AS p0
LEFT OUTER JOIN "forwards" AS f1 ON f1."post_id" = p0."id" 
INNER JOIN (SELECT id FROM users AS u0
            INNER JOIN follows AS f1 ON (f1.follower_id = $1) AND (f1.following_id = u0.id) UNION
            SELECT id FROM users AS u1 WHERE (u1.id = $1)
) AS f3 ON (p0."author_id" = f3."id") OR (f1."user_id" = f3."id") ORDER BY p0."inserted_at" DESC
Alex Castaño
  • 41
  • 1
  • 6

1 Answers1

0

You are using a LEFT OUTER JOIN, in that case if no forward exists it will set null values in the results.

See this post for more information: What is the difference between "INNER JOIN" and "OUTER JOIN"?

Simon Martinelli
  • 34,053
  • 5
  • 48
  • 82
  • I know this, thank you. The problem is that if a post has a share (forward, retweet), then the join table will have `share.user_id` always set. It does not care about if the user really follows the forwarder. – Alex Castaño Oct 04 '17 at 14:06