query mnesia data by where with 'or' - erlang

SQL:
select account from y_account where id>5
Mnesia qlc:
F = fun() ->
Q = qlc:q([E#y_account.account || E <- mnesia:table(y_account), E#y_account.id>5]),
qlc:e(Q)
end,
mnesia:transaction(F).
I can select data in mnesia like this.
But how to select data by where containing 'or', like this SQL:
select account from y_account where id>5 or name='joe'
Thanks,
Best regards

I didn't check if there is a more efficient way, but you could replace
E#y_account.id>5 by (E#y_account.id>5) orelse (E#y_account.name == "joe")

Use operator or:
F = fun() ->
Q = qlc:q([E#y_account.account ||
E <- mnesia:table(y_account), (E#y_account.id > 5) or (E#y_account.name == "joe")]),
qlc:e(Q)
end,
mnesia:transaction(F).

Related

How to select last message sent between two users from mnesia

I need to select last message sent between two users...
now with this primitive method I am selecting all messages between two users but this is long taking process
Guard = [{'=:=','$1',OID}],
Match = #pms{
from = '$1',
to = '$2',
body = '$3',
_ = '_'
},
Result = ['$$'],
{ok, Result} = mnesia:transaction(fun()->mnesia:select(pms,[{Match, Guard, [Result]}]) end),
check out the record
-record(pms,{
message_id,from,to,body,time,seen=0}).
So I have two variables there, from and to what I need is to select the last message of each conversation that user's id is either inserted into from or to
Please consider using qlc
I wrote some codes below may meet your requirement.
F = fun() ->
Q = qlc:q([E || E <- mnesia:table(pms),E#pms.from == "a",E#pms.to == "b"]),
Q2 = qlc:keysort(2, Q, [{order, descending}]),
Qc = qlc:cursor(Q2),
qlc:next_answers(Qc, 1)
end,
mnesia:transaction(F).

How to use lists:duplicate?

I would like to know if its possible to use lists:duplicate in this case:
decompress_1([])->
[];
decompress_1(L)->
MyNum = lists:map(fun(T)-> element(1,T) end,L),
Res = lists:map(fun(T)-> element(2,T) end,L).
to get :
decompress_1([{3,1},{3,2},{1,5},{1,4},{1,1},{1,0},{1,1}]) == [1,1,1,2,2,2,5,4,1,0,1]
I just manage to retrieve the first and second elements of the tuple.
There is a solution with list comprehension but I would know to do it without.
decompress([]) ->
[];
decompress(L) ->
[Y || {X, Y} <- L, _ <- lists:seq(1, X)].
Without using a list comprehension, we can use lists:duplicate/2 to create the result, but we have to flatten it to get the desired final answer:
decompress([]) ->
[];
decompress(L) ->
lists:flatten(lists:map(fun({X,Y}) ->
lists:duplicate(X,Y)
end, L)).
Without the flatten we'd get the first result shown below, instead of the second correct result:
1> decompress_no_flatten([{3,1},{3,2},{1,5},{1,4},{1,1},{1,0},{1,1}]).
[[1,1,1],[2,2,2],[5],[4],[1],[0],[1]]
2> decompress([{3,1},{3,2},{1,5},{1,4},{1,1},{1,0},{1,1}]).
[1,1,1,2,2,2,5,4,1,0,1]
By the way, you can use lists:duplicate/2 in the original list comprehension approach as well:
decompress([]) ->
[];
decompress(L) ->
[Y || {X,Y} <- L, _ <- lists:duplicate(X,Y)].
This works because here we don't use the values produced by lists:seq/2 or lists:duplicate/2, but rather we use only the number of items they produce.

How To equal <<"xxxasdew">> , and '<<"xxxasdew">>' in erlang

I am having Data like the below:
Data = [{<<"status">>,<<"success">>},
{<<"META">>,
{struct,[{<<"createdat">>,1406895903.0},
{<<"user_email">>,<<"gopikrishnajonnada#gmail.com">>},
{<<"campaign">>,<<"5IVUPHE42HP1NEYvKb7qSvpX2Cm">>}]}},
{<<"mode">>,1}]
And Now i am having a
FieldList = ['<<"5IVUPHE42HP1NEYvKb7qSvpX2Cm">>']
Now:
I am trying like the below but i am getting empty instead of the value
90> [L || L <- FieldList,proplists:get_value(<<"campaign">>,element(2,proplists:get_value(<<"META">>,Data,{[],[]}))) == L].
[]
so how to get the both values are equal and get the final value.
You can parse the atom as if it were an Erlang term:
atom_to_binary(Atom) ->
L = atom_to_list(Atom),
{ok, Tokens, _} = erl_scan:string(L ++ "."),
{ok, Result} = erl_parse:parse_term(Tokens),
Result.
You can then do
[L ||
L <- FieldList,
proplists:get_value(<<"campaign">>,
element(2,
proplists:get_value(<<"META">>,Data,{[],[]})))
== atom_to_binary(L)
].
You can also do it the other way round, (trying to) convert the binary to an atom using this function:
binary_literal_to_atom(Binary) ->
Literal = lists:flatten(io_lib:format("~p", [Binary])),
try
list_to_existing_atom(Literal)
catch
error:badarg -> undefined
end.
This function will return undefined if the atom is not known yet (s. Erlang: binary_to_atom filling up atom table space security issue for more information on this). This is fine here, since the match can only work if the atom was known before, in this case by being defined in the FieldList variable.
How did you get those values in the first place?
Data = [{<<"status">>,<<"success">>},
{<<"META">>,
{struct,[{<<"createdat">>,1406895903.0},
{<<"user_email">>,<<"gopikrishnajonnada#gmail.com">>},
{<<"campaign">>,<<"5IVUPHE42HP1NEYvKb7qSvpX2Cm">>}]
}
},
{<<"mode">>,1}].
[_,{_,{struct,InData}}|_] = Data.
[X || {<<"campaign">>,X} <- InData].
it gives you the result in the form : [<<"5IVUPHE42HP1NEYvKb7qSvpX2Cm">>]
of course you can use the same kind of code if the tuple {struct,InData} may be in a different place in the Data variable.
-module(wy).
-compile(export_all).
main() ->
Data = [{<<"status">>,<<"success">>},
{<<"META">>,
{struct,[{<<"createdat">>,1406895903.0},
{<<"user_email">>,<<"gopikrishnajonnada#gmail.com">>},
{<<"campaign">>,<<"5IVUPHE42HP1NEYvKb7qSvpX2Cm">>}]
}
},
{<<"mode">>,1}],
Fun = fun({<<"META">>, {struct, InData}}, Acc) ->
Value = proplists:get_value(<<"campaign">>, InData, []),
[Value | Acc];
(_Other, Acc)->
Acc
end,
lists:foldl(Fun, [], Data).
I think you can use this code.

Erlang List Filter Syntax

I'm trying to write some Erlang that would filter an array in the form:
[{dakota, "cold and snowy"}, {california, "perfect weather"}] % and so on
Here is what I've got - I get a syntax error when I try to make a .beam from werl.
-module(matcher).
-export([findkeywords/2]).
findkeywords(Word, Arr) ->
IsMatch = fun({Key, Desc}) ->
lists:any(fun(X) -> X==Word end, string:tokens(Desc, " ")),
lists:filter(IsMatch, [{K, V} || {K, V} <- Arr]).
Can anyone spot where my syntax is off?
I saw your call to arms on twitter and just had to come take a look. :D
If you want this to compile, you're just missing an end on your fun on line 6. Add it in and it compiles without complaint.
-module(matcher).
-export([findkeywords/2]).
findkeywords(Word, Arr) ->
IsMatch = fun({Key, Desc}) ->
lists:any(fun(X) -> X==Word end, string:tokens(Desc, " ")) end, % ADD THE END HERE
lists:filter(IsMatch, [{K, V} || {K, V} <- Arr]).
You can clean this up a bit too, unless this is an exercise in string matching for yourself. The string module has str(String, SubString) -> Index and rstr(String, SubString) -> Index that are described as such in the Erlang Manual:
Returns the position where the first/last occurrence of SubString begins in String. 0 is returned if SubString does not exist in String. For example:
> string:str(" Hello Hello World World ", "Hello World").
8
Using this tidies it up a bit, and you could even shorten the whole thing into a one liner. The list comprehension is unnecessary as the data is already in the format that you're trying to feed it in.
-module(matcher).
-export([findkeywords/2]).
findkeywords(Word, Arr) ->
lists:filter(fun({_Key, Desc}) -> string:str(Desc, Word) > 0 end, Arr).
You miss one "end" from the two functions. Also, it looks like the list comprehension in this example used is not needed.
findkeywords(Word, Arr) ->
IsMatch =
fun({_, Desc}) -> lists:any(fun(X) -> X == Word end, string:tokens(Desc, " ")) end,
lists:filter(IsMatch, [{K, V} || {K, V} <- Arr]).
You are missing the end key word for one of the funs. However, looks like you are searching within strings. This is normally what is use
-define(DATA,[{dakota, "cold and snowy"}, {california, "perfect weather"}]).
string_contains(Big,Small)-> string:rstr(Big,Small) > 0.
findkeywords(Word)-> [X || X <- ?DATA,string_contains(element(2,X),Word) == true].
Anyway, one of your funs was not ended well. that's all.

Erlang: join two tables not on equality pattern

Is there a way to implement
SELECT *
FROM pattern p
JOIN tag t ON t.tag LIKE CONCAT(p.pattern, '%') AND t.type = p.type
in terms of erlang qlc on top of two ets:
[{{Pattern, Type}, Id}]
[{{Tag, Type}, Id}]
?
I. e. inequality pattern meaning Tag begins with Pattern and Type = Type.
Thanks in advance.
Pretty simple:
1> ets:new(a,[named_table]),[ets:insert(a,X) || X<-[{{"foo", bar},12},{{"baz", quux},11}]].
[true,true]
2> ets:new(b,[named_table]),[ets:insert(b,X) || X<-[{{"foobar", bar},12},{{"bazquux", quux},11},{{"fooxxx", bar},1},{{"bazbaz", baz},11}]].
[true,true,true,true]
3> qlc:e(qlc:q([{Pattern, Type1, Tag, Id1, Id2} || {{Pattern, Type1}, Id1} <- ets:table(a), {{Tag, Type2}, Id2} <- ets:table(b), Type1 =:= Type2, lists:prefix(Pattern, Tag)])).
[{"baz",quux,"bazquux",11,11},
{"foo",bar,"foobar",12,12},
{"foo",bar,"fooxxx",12,1}]

Resources