Help please solve the following situation:

There are two kinds of API where message history is stored, it's Zopim and Chat2Desc (import into Postman). While these two but can then others appear.

And my database with the users table:

Table users
id , email, phone, ...

In Zopim, users are identified via email, and in Chat2Desc through the phone. For me, these two fields are important, whatever the chat was and how many would not be.

That is, if I receive an email or a user's phone in messages, I make a request to my database (table users) to identify my user.

And in principle, even the structure of chat rooms is not important.I'll somehow choose them.And here's how to properly save them, so much so that I had one structure for everyone.

And that's what I came up with (Something I don't like, especially the chat_clients table): enter image description here


Table chats (Data for chat):

  1. client_id - indicates the id of the chat_clients table
  2. duration - the duration of the chat (120 seconds)
  3. system_type - stores the name of the chat (Zopim, Chat2Desc, ...)
  4. created_at - creation date

Table chat_clients (information about users who were in the chat):

  1. is_agent - 0 | 1: 1 => my user, 0 => not my
  2. user_id - is the user id. Contains either id from the users table or empty.
  3. assigned_data - those initials under which users were in the chat
  4. bean_module - it does not matter (information about my user)
  5. unique_col - There will either be a email (from Zopim) or a phone (from Chat2Desc, Or I think to store the id of the users table). Will guarantee the uniqueness of the values.

The users_id + unique_col bunch is unique (UNIQUE KEY user_id_unique_col_UQ (user_id, unique_col))

Table chat_messages:

  1. text - the text of the message.
  2. client_id - indicates the id of the chat_clients table
  3. chat_id - indicates the id of the table chats
  4. file_id - indicates the id of the chat_files table
  5. transport - the value will be for Chat2Desc (Viber, WhatsApp, ...), for Zopim, so it's not empty, Zopim

Table chat_files Information about the transferred files in the chat. Analogical tables may be not to store additional information.

In the future I'm going to select the history of correspondence for each user.

Q: How can I improve the structure of tables to get more flexibility ?

Thank you in advance.

  • 1
    Flexibility for what? I suppose you should explain what is typical use and goals of this database. For example if you want to stream chat history to clients, it may gain speed by further normalisation, but if you want to focus on chat history statistical reporting, you should denormalize it. What is typical querying pattern?
    – kakaz
    Dec 1, 2017 at 19:42
  • 3
    Write the SELECTs; you will either find that it is flexible enough, or you will find out more specifics about what is inflexible.
    – Rick James
    Dec 1, 2017 at 22:59
  • @kakaz In the future I'm going to select the history of correspondence for each user. Dec 2, 2017 at 18:20
  • 1
    This scheme does not support replies, do you need replies? This is flat and chronological with no concept of targeting or threads. Dec 8, 2017 at 2:55
  • @EvanCarroll do you need replies? Yes. Dec 8, 2017 at 7:12

3 Answers 3


All modern chatting interfaces, without exception, implement a hierarchical and a not-chronological schema for chat. That means you have to use (the soon to be released) MySQL 8, as prior versions do not support recursive CTEs which are required to do this. Any workaround can't permit infinite depth, which is usually required or at the very least nice to have.

Rather than drawing up a schema here, you can see what one looks like in PostgreSQL here, where I answered a similar question. Essentially, each message has id|parent_id the parent_id points to the id on the same table. This creates a . We call this implementation of hierarchy "self-referential", or "single-table hierarchy."

Moreover, you may wish to implement an array of tagged users or the like for better indexing.

Ultimately, if you're going to go down this route and you have no prior work, you should be using PostgreSQL -- which supports Recursive CTE's now, and sql-array's for easy tagging.

I'm not saying your schema has to look like those. You may have additional demands, but I wouldn't want to start off with an inferior feature set and the wrong tool.

For clarity this critique is specific to your chat_messages table. The chat sessioning would be done by just creating a seperate table for it, and linking all messages to an entry in that table. For instance,

CREATE TABLE chat_session (
  chat_session_id  int  PRIMARY KEY

Other tables..

CREATE TABLE chat_message (
  ts                             timestamp with time zone,
  chat_message_id                int PRIMARY KEY,
  chat_message_parent_id         int REFERENCES chat_message,
  chat_message_author_user_id    int REFERENCES user,
  chat_message_author_client_id  int REFERENCES client

Or the like.

  • What if two people submitted a message at the same time? Should they both share the same parent or should one be the child of the other? If the latter, how would you manage this?
    – Strawberry
    Jun 11, 2018 at 10:16

First of all, the relationship between tables chats and chat_clients is the wrong way. You want many chat_clients per chats, so therefore you should remove client_id from the chats table and add chat_id to the chat_clients table. This would then be a foreign key to chats(id).

Similarly, the relationship between chat_messages and chat_files is the wrong way - you want (potentially) many files per message. So remove chat_messages.file_id and add chat_files.chat_message_id, and make that an explicit foreign key.

You should add an id column (primary key) to the users table, and make chat_clients.user_id be a foreign key to that.

You may in the future find that you need to store more information, e.g. for the users. You can then add extra columns as the requirements become clearer (which is usually not a problem, especially with the right tools such as pt-online-schema-change), or you can anticipate these requirements now by adding more general-purpose columns that your application then has to "decode" or interpret. If you're using MySQL 5.7+ then you can even use the JSON data type and store JSON data in these columns.

  • add chat_id to the chat_clients table : Chat has many clients and vice versa. Dec 9, 2017 at 20:45

Client-side database

Quite effective in minimizing the data stored in the database by holding the data within the device like WhatsApp & Viber. For the mobile application, it’s the best way to design the database.

Server side chat storage

Server-side database

Web chat providers for collaboration in the market like Slack, Hipchat are built on the server-side database. For online communities based setup, it suits very well.

Client side chat storage

For more see here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.