Laravel 5.4 formatting result set - mysql

Can someone help me convert this query so that my result set is in different format?
$sessions = new Session();
$results = $sessions->where('session_status', $status)->where('application_period_id', (int) ApplicationPeriod::all()->last()->id)->get()->pluck('speaker_id');
$speakers = Speaker::whereIn('id', $results)
->with('session.audiancesession.audiances')
->with('session.subjectsession.subjects')
->with(['session' =>
function ($query) use($status) {
$query->where('session_status', '=', $status);
}])->orderBy('last_name')->get();
This is requested via Ajax(axios)... Now this is how result is formatted:
Obj->data(array of objects)->[0]->name
->address
->session(array of objects)
->[0]->time
->fee
My issue is that my session parameter is array and there can only ever be (1) so I don't need to to be an array and I would like to have object (json) instead.
Thank you!

You might have more success if you change your client-side code to work with an array of sessions each session having its speaker, that means your original query would be like
$sessions = Sessions::with([
'speaker', 'audiancesession.audiances', 'subjectsession.subjects'
])->where('application_period_id', (int) ApplicationPeriod::orderBy('id','DESC')->first())->get();
Note the order by -> first in the ApplicationPeriod makes it so you don't have to get all application periods from the database to memory.
Then your client side should handle an array of sessions.
You can transform the above slightly using to get a similar result to what you need:
$speakers = $sessions->map(function ($session) {
$speaker = collect($session->speaker->toArray());
$speaker->put('session', collect($session->toArray())->except('speaker'));
return $speaker;
})->orderBy('last_name','DESC');
Though I wouldn't guarantee the result here as I've not tested it on your (complex looking) data.

Related

Get SQL array from ActiveRecord::Relation

I'm building up a query like this:
scope = User.select(:name).where("name = ?", 'test')
In another part of my code, I'm trying to convert scope, which is an ActiveRecord::Relation object into a SQL array like ["SELECT name FROM users WHERE name = ?", 'test']. Is there any way to accomplish this? Thanks in advance.
It doesn't appear to be possible to get the array you want back from an ActiveRecord::Relation object.
Say that we're just using where. When we call User.where("name = ?", "test") we enter the where method in ActiveRecord::QueryMethods. This calls where! which calls build_where. Since we passed in the query as a String we end up here:
# ActiveRecord::QueryMethods#build_where
when String, Array
[#klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
sanitize_sql combines the SQL query with the values and the result is stored in where_values:
> User.where("name = ?", "test").where_values
=> ["name = 'test'"]
ActiveRecord::Relation only holds onto this combined version, not the query and values separately.

Codeigniter -> 2 variables inside a controller

I am trying to set up a filter on my website. Here, I am trying to pass (2) variables (neighborhood and business category). My problem is when only (1) of them is true and the other is false or one variable does not exist. I am trying to pull this data from my URL
mydomain.com/controller/function/neighbrohood/biz-category
which translates
mydomain.com/ny/find/$neighborhood/$biz_filter
When I have both variables then there is no problem.
How do I resolve the page with only 1 of the 2 variables there?
Here is my model:
public function search($neighborhood = null, $biz_filter = null) {
$neighborhood = $this->uri->segment(3);
$biz_filter = $this->uri->segment(4);
// SELECT
$this->db->select('*');
// MAIN TABLE TO GRAB DATA
$this->db->from('biz');
// TABLES TO JOIN
$this->db->join('city', 'city.city_id = biz.biz_cityID');
$this->db->join('zip', 'zip.zip_id = biz.biz_zipID', 'zip.zip_cityID = city.city_id');
$this->db->join('state', 'state.state_id = city.city_stateID');
$this->db->join('neighborhood', 'biz.biz_neighborhoodID = neighborhood.neighborhood_id');
$this->db->join('biz_filter', 'biz_filter.bizfilter_bizID = biz.biz_id');
$this->db->join('biz_category', 'biz_filter.bizfilter_bizcategoryID = biz_category.bizcategory_id');
// RETURN VARIABLES
$this->db->where('neighborhood.neighborhood_slug', $neighborhood);
$this->db->where('biz_category.bizcategory_slug', $biz_filter);
// ORDER OF THE RESULTS
$this->db->order_by('biz_name asc');
// RUN QUERY
$query = $this->db->get();
// IF MORE THAN 0 ROWS ELSE DISPLAY 404 ERROR PAGE
if($query->num_rows() > 0){
return $query;
} else {
show_404('page');
}
}
Example. Say I am looking for a Restaurant in Little Italy:
URL = mydomain.com/ny/find/little-italy/restuarants
This part, I can resolve the query correctly and display the data. The issue is when there is no neighborhood or no category, I cannot figure out how to resolve the data.
I am new to codeigniter and a self-taught programmer, trying to figure this out as I go. Any help would be much appreciated.
Thank you in advance.
first of all it is optional to get the variables from the uri
$neighborhood = $this->uri->segment(3);
$biz_filter = $this->uri->segment(4);
You already have that from your function parameter.
You can check the condition where your $neighborhood or $biz_filter is available or not then you can use condition in your query.
Something like this
if($neighborhood) { // query for neighborhood } elseif($biz_filter) {}
Thanks
First of all you should get the variable values from your controller not your model, you should then pass such values to your controller from your model, its bad coding practice to allow your view interact with the model.
Also, if you want a value of "-" set for the variable. You should set "-" as the return value right from the parameters being passed to the controller.
What you should do is go to your controller and give it the two parameters, set default values for both and also go to your model and make it receive two parameters also, pass the parameters to the model when calling from the controller. Then get back if there are any more errors.

Loop through query results without loading them all in array in Codeigniter [duplicate]

The normal result() method described in the documentation appears to load all records immediately. My application needs to load about 30,000 rows, and one at a time, submit them to a third-party search index API. Obviously loading everything into memory at once doesn't work well (errors out because of too much memory).
So my question is, how can I achieve the effect of the conventional MySQLi API method, in which you load one row at a time in a loop?
Here is something you can do.
while ($row = $result->_fetch_object()) {
$data = array(
'id' => $row->id
'some_value' => $row->some_field_name
);
// send row data to whatever api
$this->send_data_to_api($data);
}
This will get one row at the time. Check the CodeIgniter source code, and you will see that they will do this when you execute the result() method.
For those who want to save memory on large result-set:
Since CodeIgniter 3.0.0,
There is a unbuffered_row function,
All the methods above will load the whole result into memory (prefetching). Use unbuffered_row() for processing large result sets.
This method returns a single result row without prefetching the whole result in memory as row() does. If your query has more than one row, it returns the current row and moves the internal data pointer ahead.
$query = $this->db->query("YOUR QUERY");
while ($row = $query->unbuffered_row())
{
echo $row->title;
echo $row->name;
echo $row->body;
}
You can optionally pass ‘object’ (default) or ‘array’ in order to specify the returned value’s type:
$query->unbuffered_row(); // object
$query->unbuffered_row('object'); // object
$query->unbuffered_row('array'); // associative array
Official Document: https://www.codeigniter.com/userguide3/database/results.html#id2
Well, the thing is that result() gives away the entire reply of the query. row() simply fetches the first case and dumps the rest. However the query can still fetched 30 000 rows regardles of which function you use.
One design that would fit your cause would be:
$offset = (int)#$_GET['offset'];
$query = $this-db->query("SELECT * FROM table LIMIT ?, 1", array($offset));
$row = $query->row();
if ($row) {
/* Run api with values */
redirect(current_url().'?offset'.($offset + 1));
}
This would take one row, send it to api, update the page and use the next row. It will alos prevent the page from having a timeout. However it would most likely take a while with 30 000 records and refreshes, so you may wanna adjust your LIMIT ?, 1 to a higher number than 1 and go result() and foreach() multiple apis per pageload.
Well, there'se the row() method, which returns just one row as an object, or the row_array() method, which does the same but returns an array (of course).
So you could do something like
$sql = "SELECT * FROM yourtable";
$resultSet = $this->db->query($sql);
$total = $resultSet->num_rows();
for($i=0;$i<$total;$i++) {
$row = $resultSet->row_array($i);
}
This fetches in a loop each row from the whole result set.
Which is about the same as fetching everyting and looping over the $this->db->query($sql)->result() method calls I believe.
If you want a row at a time either you make 30.000 calls, or you select all the results and fetch them one at a time or you fetch all and walk over the array. I can't see any way out now.

Why is count(id) resulting 3 dimensional array?

Im using this direct query method in cakephp to get a count (against the norms of MVC).
$count = $this->History->query("SELECT count(id) AS x FROM ratings WHERE id='3' AND employee='28'");
But it turns out that, i need to use $count[0][0]['x'] to get the value.
Why isnt it available at $count['x']?
in your case it will return it in a general way: 0 = iterate over all models, and again 0 since you dont have a specific model name). your result will always be in $count[0][0]['fieldname'] then.
it is highly recommended to always use the wrapper methods if possible.
why are you not using the cakephp database wrapper methods as documented?
$count = $this->History->find('count', array('conditions'=>array('id'=>3, 'employee'=>28));
?
it would result in the expected output x
Simply, its because the function
$this->History->query(....);
does not return a single dimensional array. I will suggest you to create a helper function, which extracts the single dimensional array and return it.
function single_query($query) {
$result = $this->History->query($query);
return $result[0][0];
}
then use it
$count = $this->single_query("SELECT count(id) AS x FROM ratings WHERE id='3' AND employee='28'");

How to get Ruby MySQL returning PHP like DB SELECT result

So I use the PDO for a DB connection like this:
$this->dsn[$key] = array('mysql:host=' . $creds['SRVR'] . ';dbname=' . $db, $creds['USER'], $creds['PWD']);
$this->db[$key] = new PDO($this->dsn[$key]);
Using PDO I can then execute a MySQL SELECT using something like this:
$sql = "SELECT * FROM table WHERE id = ?";
$st = $db->prepare($sql);
$st->execute($id);
$result = $st->fetchAll();
The $result variable will then return an array of arrays where each row is given a incremental key - the first row having the array key 0. And then that data will have an array the DB data like this:
$result (array(2)
[0]=>[0=>1, "id"=>1, 1=>"stuff", "field1"=>"stuff", 2=>"more stuff", "field2"=>"more stuff" ...],
[1]=>[0=>2, "id"=>2, 1=>"yet more stuff", "field1"=>"yet more stuff", 2=>"even more stuff", "field2"=>"even more stuff"]);
In this example the DB table's field names would be id, field1 and field2. And the result allows you to spin through the array of data rows and then access the data using either a index (0, 1, 2) or the field name ("id", "field1", "field2"). Most of the time I prefer to access the data via the field names but access via both means is useful.
So I'm learning the ruby-mysql gem right now and I can retrieve the data from the DB. However, I cannot get the field names. I could probably extract it from the SQL statement given but that requires a fair bit of coding for error trapping and only works so long as I'm not using SELECT * FROM ... as my SELECT statement.
So I'm using a table full of State names and their abbreviations for my testing. When I use "SELECT State, Abbr FROM states" with the following code
st = #db.prepare(sql)
if empty(where)
st.execute()
else
st.execute(where)
end
rows = []
while row = st.fetch do
rows << row
end
st.close
return rows
I get a result like this:
[["Alabama", "AL"], ["Alaska", "AK"], ...]
And I'm wanting a result like this:
[[0=>"Alabama", "State"=>"Alabama", 1=>"AL", "Abbr"=>"AL"], ...]
I'm guessing I don't have the way inspect would display it quite right but I'm hoping you get the idea by now.
Anyway to do this? I've seen some reference to doing this type of thing but it appears to require the DBI module. I guess that isn't the end of the world but is that the only way? Or can I do it with ruby-mysql alone?
I've been digging into all the methods I can find without success. Hopefully you guys can help.
Thanks
Gabe
You can do this yourself without too much effort:
expanded_rows = rows.map do |r|
{ 0 => r[0], 'State' => r[0], 1 => r[1], 'Abbr' => r[1] }
end
Or a more general approach that you could wrap up in a method:
columns = ['State', 'Abbr']
expanded_rows = rows.map do |r|
0.upto(names.length - 1).each_with_object({}) do |i, h|
h[names[i]] = h[i] = r[i]
end
end
So you could collect up the rows as you are now and then pump that array of arrays through something like what's above and you should get the sort of data structure you're looking for out the other side.
There are other methods on the row you get from st.fetch as well:
http://rubydoc.info/gems/mysql/2.8.1/Mysql/Result
But you'll have to experiment a little to see what exactly they return as the documentation is, um, a little thin.
You should be able to get the column names out of row or st:
http://rubydoc.info/gems/mysql/2.8.1/Mysql/Stmt
but again, you'll have to experiment to figure out the API. Sorry, I don't have anything set up to play around with the MySQL API that you're using so I can't be more specific.
I realize that php programmers are all cowboys who think using a db layer is cheating, but you should really consider activerecord.