silverdr

silverdr

Ecto.Schema / Ecto.Changeset - optional, conditionally present fields

I have a – let’s call it ‘Parent’ schema, which embeds_one child schema. Basically a set of largely mutually exclusive key/value pairs. Something like (simplified here - actual schema is far larger):

		field :type, :string
		field :time, :time
		field :dom, :integer
		field :dow, :integer

Depending on the value in :type one of the following fields is required, while others are not relevant. I do all the casting, validating, including conditional validate_required in custom validating functions and I end up with a ready to use, valid changeset that gets persisted in a JSON field in the DB.

The problem is that ALL the fields get stored, even if they are not needed. I would like to have only the relevant fields to end up in the DB but at best I get something like:

{
  "type": "dow", 
  "time": null,
  "dom": null,
  "dow": 1
}

What can I do to have only

{
  "type": "dow", 
  "dow": 1
}

persisted, instead?

Most Liked

dimitarvp

dimitarvp

Instead of embedding a record, can’t you just have that be a free-from singular JSON field whose contents depend on the type column? That’s what I would do because that would also emulate pretty closely what strongly statically typed languages do with sum types (enums in Rust).

garrison

garrison

What you’re really looking for here is a “polymorphic embedded schema”, which is something that comes up every so often. I think someone even wrote a library for it, though I’ve never used it.

My personal opinion: If your data is unstructured, just use a map field (JSON column) and don’t worry so much about the schema - that’s what unstructured means, after all!

If your data is structured and you are worried about the schema, then you should probably be using actual tables. That’s what they’re for!

Of course, if you wanted to go in the opposite direction with an even more degenerate solution, I bet you could put the embedded schema in a virtual field and then parse it back out at the end of the parent’s changeset, drop the nulls, and dump it into a real map field. Of course, then your data wouldn’t be structured on the way out of the DB, but you could probably cook up a solution to that too if you really wanted. The Ecto.Type hack is probably better, though.

silverdr

silverdr

The question is “how”. I don’t see any straightforward path towards that, unless I drop the embeds_one from my “parent” model.

I see, roger.

Thanks for pointing out. This doesn’t bother me that much though as this config is read-heavy. If it’s get completely replaced once in a while doesn’t matter so much as reading it “all the time”.

Yup, precisely that.

No, I don’t :slight_smile: I index data, by which I want to retrieve (possibly aggregated) information. I don’t need to aggregate any information on configs as of now :wink:

It does. While I am not in the thousand keys range and don’t expect to ever get there. The hundred one doesn’t seem completely improbable. Which is the main reason I started this thread – how do I store only what is needed for a given configuration rather than just “everything”, including 90% of noise.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement