I have a messaging app where users can send multiple types of messages (text, video, image, etc). I would like to model these with different schemas, but I need to be able to query them and get back one list of all types of messages. What would be the best way to go about modeling this?
My initial thought is to have a table that contains all the columns for every type of message, and then to have multiple schemas that act on the same table, for example TextMessage, VideoMessage, ImageMessage, etc.
It would be really nice if I could then return a list of all messages in the form of:
At this point I’m still using a one large schema that looks a bit like this:
schema "messages" do
field :type, DB.MessageType, default: :text
field :text, :string
field :video_url, :string
field :image_url, :string
...
end
The DB.MessageType is a custom Ecto type that basically translates :text, :video, and :image in the struct to "text", “video”, and “image” in the database, and only lets messages with those values be inserted.
We’ve done this at my company with really bad results. Here’s how I would have done it differently.
In your first phase, design your app with plain ole’ Structs. This is nice because you can focus on the problem without all the DB issues sneaking in. Write it to solve the application problem you have. You can make a Protocol (or behaviour) to handle all the polymorphism you want.
Once your app is going, now think about how you want to persist those structs. Put in a layer which takes those structs in and read/writes them to a database structure that is hidden from the caller. As much as possible, don’t let Ecto concepts leak out of that layer.
In other words, use Ecto for saving and loading data, but don’t pass Structs generated by Ecto.Schema through the core of your application. Make your own Structs in your application core and pass those around.
Wow, thanks for the advice. I’m running into this problem right now myself – focusing too much on how I should represent my data in ecto when I should really be focusing on how to represent it in the application itself.
I have to wonder whether this is more of a process issue. Structs are great logical representations of the various shapes within your data but they lack the convenience of ChangeSet that many developers seem to crave. Maybe what is really needed is that ChangeSet and it’s schema facility are separated from Ecto and a workflow that emphasizes application schema first (rather than DB schema) is established. I suspect that consequently application schema to DB schema generation/mapping may become a little more complex.