Searching through databases serialized column - mysql

In MySQL Rails 3 application, one of my columns are serialized to Hash. My question is simple: how can I get results based on this column?
I tried this approach:
example_hash = {id: 666}
ExampleTable.last.hash == example_hash
:true ###### Here you can see that both hashes are the same
Still, a query like this give me no results and no exceptions:
ExampleTable.where('hash LIKE ?', example_hash)
It just doesn't detect the record I need.

my_hash = {id:666}
search_term = my_hash.serializable_hash
ExampleTable.where(search_term)
I tried this in an existing Rails 4 app. You will have to test if it works in Rails 3. I don't have include ActiveModel::Serialization in my model and it still works.
Here is my console session:
Loading development environment (Rails 4.0.0)
$pry(main)> t = Tool.first
Tool Load (10.9ms) SELECT "tools".* FROM "tools" ORDER BY "tools"."id" ASC LIMIT 1
=> #<Tool id: 2, name: "6", serial: "134989652", purchased: nil, put_in_service: nil, cost: nil, value: nil, in_service: true, retired: nil, created_at: "2013-07-17 06:12:59", updated_at: "2014-02-13 17:19:10", note: "", condition: "5 - Brand New Condition", old_location: "Sta 75", model: "Stihl 066", loaner: false, location_id: 9, category_id: 2, annual_service: false>
$pry(main)> x = t.serializable_hash
=> {"id"=>2,
"name"=>"6",
"serial"=>"134989652",
"purchased"=>nil,
"put_in_service"=>nil,
"cost"=>nil,
"value"=>nil,
"in_service"=>true,
"retired"=>nil,
"created_at"=>Tue, 16 Jul 2013 23:12:59 PDT -07:00,
"updated_at"=>Thu, 13 Feb 2014 09:19:10 PST -08:00,
"note"=>"",
"condition"=>"5 - Brand New Condition",
"old_location"=>"Sta 75",
"model"=>"Stihl 066",
"loaner"=>false,
"location_id"=>9,
"category_id"=>2,
"annual_service"=>false}
$pry(main)> Tool.where(x)
Tool Load (10.3ms) SELECT "tools".* FROM "tools" WHERE "tools"."id" = 2 AND "tools"."name" = '6' AND "tools"."serial" = '134989652' AND "tools"."purchased" IS NULL AND "tools"."put_in_service" IS NULL AND "tools"."cost" IS NULL AND "tools"."value" IS NULL AND "tools"."in_service" = 't' AND "tools"."retired" IS NULL AND "tools"."created_at" = '2013-07-17 06:12:59.638381' AND "tools"."updated_at" = '2014-02-13 17:19:10.674233' AND "tools"."note" = '' AND "tools"."condition" = '5 - Brand New Condition' AND "tools"."old_location" = 'Sta 75' AND "tools"."model" = 'Stihl 066' AND "tools"."loaner" = 'f' AND "tools"."location_id" = 9 AND "tools"."category_id" = 2 AND "tools"."annual_service" = 'f'
=> [#<Tool id: 2, name: "6", serial: "134989652", purchased: nil, put_in_service: nil, cost: nil, value: nil, in_service: true, retired: nil, created_at: "2013-07-17 06:12:59", updated_at: "2014-02-13 17:19:10", note: "", condition: "5 - Brand New Condition", old_location: "Sta 75", model: "Stihl 066", loaner: false, location_id: 9, category_id: 2, annual_service: false>]

Related

trying to group by artist using Sequelize and NodeJs

I have a simple Mysql table like the following fields:
Id, songName, ArtistName, siglosID
example data:
1 My Way Frank Sinatra 1
2 Big Balls ACDC 2
3 New York Frank Sinatra 3
4 Highway To Hell ACDC 4
I want to return an object to return to graphql where data is grouped by artistName
something like the following:
[ artistName: 'ACDC':[
{ id: 2, songName: 'Big Balls', artistName: 'ACDC', siglosId: '2' },
{ id: 4, songName: 'Highway To Hell', artistName: 'ACDC', siglosId: '4' },],
[ artistName: 'Frank Sinatra':[
{ id: 3, songName: 'New York', artistName: 'Frank Sinatra', siglosId: '3' },
{ id: 1, songName: 'My Way', artistName: 'Frank Sinatra', siglosId: '1' },],
]
What I actually get back:
[
{ id: 2, songName: 'Big Balls', artistName: 'ACDC', siglosId: '2' },
{
id: 1,
songName: 'My Way',
artistName: 'Frank Sinatra',
siglosId: '1'
}
Not sure how to use group properly or do I need to use a join?
My code:
getAllSongs: {
type: new GraphQLList(SongType),
async resolve() {
const mytest = await dbSong.findAll({
order: ["artistName"],
group: ["artistName"],
raw: true,
});
console.log("test Songs grouped by artist: ", mytest);
// return dbSong.findAll({ raw: true });
return dbSong.findAll({
order: ["artistName"],
group: ["artistName"],
raw: true,
});
},
},
},
});`

How to get all posts in a table with comments and author data

I have three different tables:
users
posts
comments
And I would like to get a result like this:
posts: [
{
id: 1,
text: "Looking for something else specific here",
author: {
id: 3,
image: "https://lh3.googleusercontent.com",
username: "AR"
},
comments: [
{
id: 1,
text: 'Try this!',
author: {
id: 4,
image: "https://lh3.googleusercontent.com",
username: "AM"
}
},
{
id: 2,
text: 'Thanks!',
author: {
id: 3,
image: "https://lh3.googleusercontent.com",
username: "AR"
}
},
],
created_at: "2021-08-18 01:16:58.000000",
updated_at: "2021-08-18 01:16:58.000000"
},
{
id: 2,
text: "Looking for something specific here",
author: {
id: 4,
image: "https://lh3.googleusercontent.com",
username: "AM"
},
comments: [
null
],
created_at: "2021-08-18 01:18:13.000000",
updated_at: "2021-08-18 01:18:13.000000"
}
]
So far I have this:
SELECT
cast(concat('[', group_concat(
JSON_OBJECT(
'id', p.id,
'text', p.text,
'author', JSON_OBJECT(
'id', u.id,
'username', u.ofdb_username,
'image', u.image
),
'comments', JSON_OBJECT(
'id', c.id,
'text', c.text,
'created_at', c.created_at,
'updated_at', c.updated_at
),
'created_at', p.created_at,
'updated_at', p.updated_at
) SEPARATOR ','), ']') as json) as posts
FROM posts as p
LEFT JOIN users as u
ON p.users_id = u.id
LEFT JOIN comments as c
on c.posts_id = p.id
However if there is more than one comment, the same post is repeated twice because of the LEFT JOIN. I also haven't tried to join users a second time to get the comment's author data.
Since I was using Next.js, I ended up switching to Prisma's ORM model which made this so much easier.
I know this isn't a direct answer but to all futurecomers: try to forgo writing SQL code and use an ORM like Prisma.

Better way to extract json map into struct

I'm new to elixir and I want to parse a json file. One of the parts is a question answer array of objects.
[
{
"questionId":1,
"question":"Information: Personal Information: First Name",
"answer":"Joe"
},
{
"questionId":3,
"question":"Information: Personal Information: Last Name",
"answer":"Smith"
},
...
]
I know what questionId's I want and I'm going to make a map for 1 = First Name, 2 = Last Name.
But currently I'm doing the following to put the data into the struct.
defmodule Student do
defstruct first_name: nil, last_name: nil, student_number: nil
defguard is_first_name(id) when id == 1
defguard is_last_name(id) when id == 3
defguard is_student_number(id) when id == 7
end
defmodule AFMC do
import Student
#moduledoc """
Documentation for AFMC.
"""
#doc """
Hello world.
## Examples
iex> AFMC.hello
:world
"""
def main do
get_json()
|> get_outgoing_applications
end
def get_json do
with {:ok, body} <- File.read("./lib/afmc_import.txt"),
{:ok,body} <- Poison.Parser.parse(body), do: {:ok,body}
end
def get_outgoing_applications(map) do
{:ok,body} = map
out_application = get_in(body,["outgoingApplications"])
Enum.at(out_application,0)
|> get_in(["answers"])
|> get_person
end
def get_person(answers) do
student = Enum.reduce(answers,%Student{},fn(answer,acc) ->
if Student.is_first_name(answer["questionId"]) do
acc = %{acc | first_name: answer["answer"]}
end
if Student.is_last_name(answer["questionId"]) do
acc = %{acc | last_name: answer["answer"]}
end
if Student.is_student_number(answer["questionId"]) do
acc = %{acc | student_number: answer["answer"]}
end
acc
end)
IO.inspect "test"
s
end
end
I'm wondering what is a better way to do get_person with out having to do if statements. If I know I will be mapping 1 to questionId 1 in the array of objects.
The data will then be saved into a DB.
Thanks
I'd store a mapping of id to field name. With that you don't need any if inside the reduce. Some pattern matching will also make it unnecessary to do answer["questionId"] etc.
defmodule Student do
defstruct first_name: nil, last_name: nil, student_number: nil
#fields %{
1 => :first_name,
3 => :last_name,
7 => :student_number
}
def parse(answers) do
Enum.reduce(answers, %Student{}, fn %{"questionId" => id, "answer" => answer}, acc ->
%{acc | #fields[id] => answer}
end)
end
end
IO.inspect(
Student.parse([
%{"questionId" => 1, "question" => "", "answer" => "Joe"},
%{"questionId" => 3, "question" => "", "answer" => "Smith"},
%{"questionId" => 7, "question" => "", "answer" => "123"}
])
)
Output:
%Student{first_name: "Joe", last_name: "Smith", student_number: "123"}
Edit: to skip ids not present in the map, change:
%{acc | #fields[id] => answer}
to:
if field = #fields[id], do: %{acc | field => answer}, else: acc

Query has_many relationship, contains this and also this

# engine.rb
has_many :pistons
#piston.rb
belongs_to :engine
Piston has a column, piston_count and, of course, engine_id
My database has the following 7 records
Engine.all
#=> [#<Engine id: 1>, #<Engine id: 2>, #<Engine id: 3>]
Piston.all
#=> [#<Piston id: 1, engine_id: 1, piston_count: 1>, #<Piston id: 2, engine_id: 1, piston_count: 2>, #<Piston id: 2, engine_id: 2, piston_count: 1>, #<Piston id: 2, engine_id: 3, piston_count: 2>]
I want to write a query that says, return the Engine containing Pistons with a piston_count of 1 and also contains a piston_count of 2
I've tried...
engines = Engine.joins(:pistons).merge(Piston.where(piston_count: 1))
#=> [#, #]
engines.joins(:pistons).merge(Piston.where(piston_count:2))
#=> []
It returns an empty array because active record turns that into one AND clause. However, if I do an OR statement, it will return too many records. Any thoughts?
Figured it out. This takes the intersect of both Active Record Queries.
engine_ids = Engine.joins(:pistons).merge(Piston.where(piston_count: 1)).pluck(:id) & Engine.joins(:pistons).merge(Piston.where(piston_count: 2)).pluck(:id)
Then go back and retrieve all the intersects.
Engine.where(id: engine_ids)

How to "push ahead" records with a given value?

I am using Ruby on Rails 3.2.9 and MySQL. I have an Article model with a user_id attribute (this attribute represents the foreign key - id - for associated author users) and I would like to retrieve articles ordering those "for" a given author. That is, given I have following records:
<#Article id: 1, title: "Title 1", user_id: 1>
<#Article id: 2, title: "Title 2", user_id: 2>
<#Article id: 3, title: "Title 3", user_id: 1>
<#Article id: 4, title: "Title 4", user_id: 3>
<#Article id: 5, title: "Title 5", user_id: 1>
...
<#Article id: N, title: "Title N", user_id: M>
When I look for articles ordered "for" the author with id 1 (user_id = 1) then the returning articles should be ordered as-like the following:
<#Article id: 1, title: "Title 1", user_id: 1>
<#Article id: 3, title: "Title 3", user_id: 1>
<#Article id: 5, title: "Title 5", user_id: 1>
<#Article id: 2, title: "Title 2", user_id: 2>
<#Article id: 4, title: "Title 4", user_id: 3>
...
<#Article id: N, title: "Title N", user_id: M>
In other words, I am looking to retrieve all articles but making those ordered with this "priority": articles created by the given author returned first and then all other articles (that is, I would like to "push ahead" articles created by a given author).
How can I make that?
Note: I am looking for a Ruby on Rails implementation, maybe through the order method.
Your example is not that clear since you are searching for user_id 1 and a normal ordering by user_id would put those first anyway. I believe you mean to do something like:
SELECT id, title, user_id
FROM myTable
ORDER BY CASE WHEN user_id = #search_id THEN 1 ELSE 2 END, user_id
In your example above, #search_id should be 1.
Try:
Article.where(user_id: 1).order("user_id ASC").order("id ASC")
Or this:
Article.where(user_id: 1).order("user_id ASC, id ASC")
Try this ::
Select
*
from
myTable
order by
user_id, id
For a given user_id:
Select
*
from
myTable
where user_id='?'
order by
user_id, id
The query in Rails could be like this:
Article.order(Article.send(:sanitize_sql, ["IF(user_id = ?, 1, 2)", params[:user_id]]))
IF(user_id = ?, 1, 2) returns 1 or 2 for ordering articles. sanitize_sql, a private method, is used to sanitize parameters.
If params[:user_id] is always an integer, the query could be simplified to this:
Article.order("IF(user_id = #{params[:user_id].to_i}, 1, 2)")