Closed annrapid closed 2 years ago
Hi @annrapid,
You cannot use matchspecs (i.e. select
and select_raw
methods) for string/binary wildcard queries, however, you might be able to accomplish this if you store your values as charlists instead of strings, as you could match on the list values.
I also found a similar question on the Erlang mailing list, where the goal is to do a "begins with" search on charlists. I'm converting the code to Elixir for your ease below:
Table:
defmodule Movie do
use Memento.Table,
type: :ordered_set,
autoincrement: true,
attributes: [:id, :title, :year, :director]
def seed do
movies = [
%Movie{id: 1, title: 'Reservoir Dogs', year: 1992, director: 'Quentin Tarantino'},
%Movie{id: 2, title: 'Rush', year: 1991, director: 'Lili Zanuck'},
%Movie{id: 3, title: 'Jurassic Park', year: 1993, director: 'Steven Spielberg'},
%Movie{id: 4, title: 'Kill Bill', year: 2003, director: 'Quentin Tarantino'},
%Movie{id: 5, title: 'Pulp Fiction', year: 1994, director: 'Quentin Tarantino'},
%Movie{id: 6, title: 'Rush', year: 2013, director: 'Ron Howard'},
%Movie{id: 7, title: 'Jaws', year: 1975, director: 'Steven Spielberg'},
]
Memento.transaction!(fn -> Enum.each(movies, &Memento.Query.write/1) end)
end
end
Search for director name starting with "Steve":
Table.create(Movie)
Movie.seed()
match_spec = :ets.fun2ms(fn {Movie, _, _, _, [?S, ?t, ?e, ?v, ?e | _]} = record -> record end)
Memento.transaction!(fn -> Query.select_raw(Movie, match_spec, coerce: true) end)
# => [
# %Movie{id: 3, title: 'Jurassic Park', director: 'Steven Spielberg', year: 1993},
# %Movie{id: 7, title: 'Jaws', director: 'Steven Spielberg', year: 1975}
# ]
Of course, there are many challenges with this approach, so you might have to modify this quite a bit to get it working exactly according to your needs.
You can learn more about matchspecs here:
You should also take a look at the [Query.select_raw/3
]() docs to know how to use custom matchspecs in Memento. I would also highly recommend playing around with :ets.fun2ms/1
which makes it much easier to generate matchspecs.
There's another follow-up response to the question in mailing list mentioned earlier. It matches on strings and not charlists, but does a full table scan using :qlc
, which I understand is much slower than matchspecs, but there might not be a better alternative.
I don't have a lot of experience with :qlc
, so unfortunately I cannot help you translate that code to Elixir or modify it to work for your use-case. However, there are some very experienced erlangists on ElixirForum that might be able to help.
Also, if you were looking for something more like full-text search support, you won't find that in :mnesia
either as it's just a plain database that stores tuples with one of the fields as a key. It doesn't do any text indexing itself, and you'll need to add a layer on top of memento/mnesia for that.
Please do share your solution if you're able to solve it. I would really like to document it in Memento, and would probably even add it as a helper to the library.
Hi there, I am using Memento for a small project. It works great but I am lacking a small thing. Is there a way to search for a pattern ?
For example I have list of Movies containing word "Rush". So in a traditional database, we will do something like
where title like '%Rush%'
Is there something similar with Mnesia?
Regards,