How to delete ETS records older than xxx?

So I’ve got an ETS table, I have some records there. One of the values (terms) in every record is an equivalent of “updated_at”. I’d like to delete all “dormant” records, where the said field contains value lower than a predefined difference to current time in the same format. Something like WHERE <condition> in SQL I got to
https://www.erlang.org/doc/man/ets.html#match_delete-2
and also to:
https://www.erlang.org/doc/apps/erts/match_spec.html#ets-examples
but if some ETS experts out there are able to put a clue out of their heads that would make life more enjoyable again :wink:

How and at what position do you store updated_at? What type is it?

Erlang -- ets might be useful to construct a match statement, but note the warning.

# use fun2ms to get a general idea of what your match spec would look like
# here I match a record with four fields where third field is less than 100 (doesn't matter)
# and I select a constant 1
iex(4)> :ets.fun2ms fn {_, _, updated_at, _} when updated_at < 100 -> 1 end
[{{:_, :_, :"$1", :_}, [{:<, :"$1", 100}], [1]}]

iex(5)> tab = :ets.new(:tab, [])
#Reference<0.2610923153.3860463617.223839>

# I insert a record with some int (representing current time) as the third record
iex(7)> :ets.insert(tab, {"something", "something", _updated_at = System.os_time, "something"})
true

# I select the third element from records that have four elements and the third element is more than 100
iex(8)> :ets.select(tab, [{{:_, :_, :"$1", :_}, [{:>, :"$1", 100}], [:"$1"]}])
[1637256726836072000]

# same spec, but used for deletion
iex(9)> :ets.select_delete(tab, [{{:_, :_, :"$1", :_}, [{:>, :"$1", 100}], [true]}])
1

iex(10)> :ets.tab2list(tab)
[]
2 Likes

It’s an int (UNIX seconds) stored at third position (those are for some reasons indexed from one rather than zero, right?) so it would be position “3”.

Thanks. OK - so it’s a select rather than match. Do I understand correctly that match_delete/2 would not be able to cut it?

Yes, :ets.match can only match a record, that is it can check for equality/pattern of some fields, but not do guard-like checks: Erlang -- ets.

That’s not correct. match_spec’s can have guards, see: GitHub - ericmj/ex2ms: :ets.fun2ms for Elixir, translate functions to match specifications

Are you sure we’re talking the same thing? I found the match_spec documentation:
https://www.erlang.org/doc/apps/erts/match_spec.html

but (putting aside my getting around the match_spec stuff) I wasn’t able to get match_delete/2 to do what I wanted it to do. The select_delete/2 seems to work though. So if you say that match_delete/2 can do the same then I am puzzled. But if you’re saying that the match spec in general can have guards then it’s all OK but @ruslandoga was answering my question about match_delete/2

Oh. I didn’t realize the comment was specifically on match/match_delete. Yes, only match_spec supporting api has guards and such.

Another “interesting” thing is that the already mentioned Erlang docs
https://www.erlang.org/doc/apps/erts/match_spec.html#ets-examples

give their examples with single quotes, while the fun2ms – existence of which I was not aware until @ruslandoga’s excellent answer (he even guessed my record arity plus type and position of the field in question!) – returns everything “atomised”. Now, what am I missing this time, which cost me a portion of my life today? IOW - how was I supposed to know that I have to rewrite those examples using “atomised” equivalents? I am guessing this has a lot to do with Elixir / iex treating of charlists vs. what “pure” Erlang does with them?

Yes, You need to translate some syntaxes when using Erlang’s lib.

Yes, the single quotes in Erlang are atoms so the Erlang '$1’ is the same as Elixir :"$1" .

3 Likes