Table design for conversation
Don't store functionally dependent data. If you should need that for performance, you can always add a materialize view later (see below). But it's often better (and sometimes even faster) to calculate derived values in queries on the fly.

In particular, you would create many dead rows, table bloat, more work for VACUUM and nasty concurrency issues in conversation if you UPDATE that row with every new message and with every status change.

I suggest a relational model like this:

CREATE TABLE users (user_id serial PRIMARY KEY, ...)

CREATE TABLE conversation (
  conversation_ id serial PRIMARY KEY
, user_id1         int NOT NULL REFERENCES users
, user_id2         int NOT NULL REFERENCES users
-- cnt_new_msg   -- redundant
-- last_msg_id
, created_at       timestamptz NOT NULL DEFAULT now() 
);

CREATE TABLE message (
message_id      serial PRIMARY KEY
conversation_id int  NOT NULL REFERENCES conversation
sender          "char" NOT NULL CHECK (sender IN ('1', '2')
message         text NOT NULL
type            ???
unread          boolean NOT NULL DEFAULT TRUE
created_at      timestamptz NOT NULL DEFAULT now() 
);


Details for data types in the manual.
You can create a VIEW or MATERIALIZED VIEW to present conversation data like you had in mind:

CREATE VIEW conversation_plus_ct AS
SELECT c.*
     , count(m.unread OR NULL) AS cnt_new_msg
     , max(m.created_at) AS last_msg_id
FROM   conversation c
JOIN   message m USING (conversation_id);


And your query could look like this (not using the VIEW, but it could ..)

SELECT *
     , count(m.unread OR NULL) AS cnt_new_msg
     , max(m.created_at) AS last_msg_id
FROM   conversation c
LEFT   JOIN message m USING (conversation_id)
WHERE  [current_user_id] IN (user_id1, user_id2);