Laravel eloquent find max(date) with additional search criteria - php

I'm trying to figure out the best way to retrieve results from the database such that the created_at is the most recent, and also checking that another value (in this case Temps->value) matches a specific criteria..
For example (some information abbreviated)
LOCATIONS
+----+---------+
| ID | CITY |
+----+---------+
| 1 | DALLAS |
| 2 | CHICAGO |
| 3 | ATLANTA |
+----+---------+
TEMPS
+----+-------+----------+------------+
| ID | VALUE | CITY_ID | CREATED_AT |
+----+-------+----------+------------+
| 1 | 70 | 1 | 2010 |
| 2 | 95 | 1 | 2015 |
| 3 | 90 | 2 | 2010 |
| 4 | 80 | 2 | 2015 |
| 5 | 99 | 3 | 2015 |
+----+-------+----------+------------+
my location model.
class Location extends model
{
...
public function latestValue()
{
return $this->hasOne('App\Temp')->latest();
}
In this case I would only like the Locations in which the latest temperature reading is > 90..
In my controller if have
$highTemps = Location::with('latestValue')->get();
without iterating through every city explicitly, is there a way to adjust my eloquent relationship, or even use a collection method to filter the results?
I've looked at filter() but I'm not sure how to use that on a relationship. Especially if you're trying to filter 2-3 relationships deep. (imagine I'm starting off with Country->states->locations->temps->latestValue etc)
It would be great to have the initial query filter the results. But I can't figure out the combination of groupBy() and max() and having() etc to make the eloquent statement work.

I think the Relationship you are establishing, it's wrong..
The Problem is very simple if the relationship hasMany() will be used..
First all the latest entries will be fetched , followed by filtering the max out of them.
class Location extends model
{
...
public function latestValue()
{
return $this->hasMany('App\Temp')->latest();
}
rest is not that much typical i assume.

Related

Laravel get only models with current version

I have implemented custom model versioning in Laravel Framework. There is couple of columns handling it in the database table: sibling_id (links model's different versions together), version, accepted and validFrom.
For example:
| id | sibling_id | version | accepted | validFrom | ... |
|----|------------|---------|----------|------------|-----|
| 1 | 1 | 1 | 1 | 2017-12-01 | |
| 2 | 1 | 2 | 1 | 2018-06-01 | |
| 3 | 2 | 1 | 1 | 2017-12-10 | |
| 4 | 2 | 2 | 0 | 2017-12-28 | |
| 5 | 3 | 1 | 0 | 2017-12-01 | |
What I mean with current model:
model having the biggest version number within accepted and valid modals
OR version 1 if there isn't any other versions
I would like to have some way to get normally only current model grouped by sibling_id (so within this example the collection should include models 1, 3 and 5). This should work like same way than Laravel's withTrashed() function so that I can include all if I want to (for example version history).
Maybe this can be done somehow with the scopes but I felt it complicated because of the "sibling grouping" and another complex filters so I ended up to ask here.
Thanks in advance.
I think a SQL View would be easier to work with, rather than build the query with Laravel.
I'd build a view implementing the query something along:
select t.* from table as t
join (select sibling_id, MAX(version) as version from table group by sibling_id) as grouped
on grouped.sibling_id = t.sibling_id and t.version = grouped.version;
Then map another eloquent model for the view in Laravel. This way, you can just select from the table if you want to get all, or from the view if you want "unique" records.

How to filter in Sphinx

Sphinx data:
+----------+-------------+-------------+
| id | car_id | filter_id |
+----------+-------------+-------------+
| 37280991 | 4261 | 46 |
| 37280992 | 4261 | 18 |
| 37281000 | 4261 | 1 |
| 37281002 | 4261 | 28 |
| 51056314 | 4277 | 18 |
| 51056320 | 4277 | 1 |
| 51056322 | 4277 | 28 |
+----------+-------------+-------------+
I have a page that show cars and you can apply filters. I'm trying that Sphinx return the cars that have filter 1 and 46. If you take a look the above table, you will see that just one car(4261) have both filters. The problem is that I don't know how to apply this in Sphinx.
$this->cs->SetFilter('filter_id', array(1, 46)); // this don't work because show me both(4261, 4277) cars, because work like a "in"
$this->cs->SetGroupBy('car_id', SPH_GROUPBY_ATTR);
$this->cs->SetFilter('filter_id', array(1));
$this->cs->SetFilter('filter_id', array(46));
Both filters apply, and both need to match. In effect they are 'AND'ed.
Seems, misread the question, missed the fact using group by. THought using a MVA.
... so have to be a bit more creative. Alas will probably need to use SphinxQL, rather than SphinxAPI. As sphinxQL has HAVING
SELECT id,car_id FROM index WHERE filter_id IN (1,46) GROUP BY car_id HAVING COUNT(*)>1
This only includes rows where multiple documents match per car (ie matches each time using the IN clause. If there can be duplicates (like two rows with filter_id=1 then can perhaps use COUNT(DISTINCT filter_id) instead? )

Laravel 5.2 Find a Model Based on a Many-to-Many relationship

I'm having an issue with writing an eloquent query for a search function in my project.
Here are my database tables/models:
artist
| id | name |
---------------------
| 1 | Van Gogh |
| 2 | Michelangelo |
art
| id | title |
---------------------
| 1 | David |
| 2 | Starry Night |
art_artist
| id | art_id | artist_id |
---------------------------
| 1 | 1 | 2 |
| 2 | 2 | 1 |
style
| id | title |
---------------------
| 1 | Sculpture |
| 2 | Painting |
art_style
| id | art_id | style_id |
--------------------------
| 1 | 1 | 1 |
| 2 | 2 | 2 |
One artist hasMany art pieces, one art piece hasMany styles, and also hasMany artists. I have verified that the relationships work correctly. I also have a simple form that returns ids as a GET request with the variables artist and style.
So, I want to do two things in my function: First, check if the variables in the request are set (I can already do this). Then, USE ELOQUENT to query the art model based on the results of the form.
Here's an example: A user searches for a Sculpture by Michelangelo. The function queries the art database for any piece that is a sculpture by michelangelo and returns it as an art model.
The trouble is, I have absolutely no idea how to query the database based on the id of a related model. Any ideas?
I finally figured out how to do the query. First, I have to tell Eloquent I want to retrieve the artist model along with the art, THEN I can use whereHas:
$art = Art::with('artists')->whereHas('artists',function( $query ){
$query->where('artists.id',1);
})->get();

Specification List table laravel php

I'm using laravel with eloquent and I want to create a table (php) with specification for some products, like this
Models | ModelA | ModelB |
Size | 234 | 321 |
Sensitivity | 21 | - |
Temperature | 23 |
And my DB tables :
Models:
idModel | nameModel
1 | ModelA
2 | ModelB
Specs:
idSpec | titleSpec | spec | idModel
1 | Size | 234 | 1
2 | Size | 321 | 2
3 | Sensitivity | 21 | 1
4 | Temperature | 23 | 1
5 | Temperature | 23 | 2
So I want to create the table with some rules:
I want to organize it by model and by titleSpec
can't repeat the titleSpecs
if ModelA has one specific titleSpec and ModelB doesn't, it gets an '-'
if Model B and Model A has same value in the titleSpec, it gets an colspan with the value!
I'm using eloquent relationships!
My only problem is how to build this; should I change the DB structure?
This is not a job for the model! Your controller needs to organize and prepare the data for the view.

How to renumber a column in doctrine

I am developing a project in zf2 using doctrine and I need to create a method to renumber the order field so that the values are sequential. Before:
+-----+-------+--------+------------+
| id | order | item | collection |
+-----+-------+--------+------------+
| 987 | 1 | apple | fruits |
| 46 | 2 | banana | fruits |
| 394 | 7 | grape | fruits |
| 265 | 30 | pear | fruits |
| 89 | 1 | squash | vegetables |
+-----+-------+--------+------------+
After:
+-----+-------+--------+------------+
| id | order | item | collection |
+-----+-------+--------+------------+
| 987 | 1 | apple | fruits |
| 46 | 2 | banana | fruits |
| 394 | 3 | grape | fruits |
| 265 | 4 | pear | fruits |
| 89 | 1 | squash | vegetables |
+-----+-------+--------+------------+
The order sequences are by collection, but I don’t need the method to renumber the entire dataset; just the records in a particular collection.
Some of the solutions I am considering include:
Temporary Table:
Dump the pertinent records in order into a new table,
Add a field called new_order that is an autonumber field,
Join the tables on the id field and update current_table.order =
new_table.new_order,
Delete the temporary table.
Cycle Through the Records and Update one at a Time:
$collection = … // results from select query where collection=fruits
n = 1;
For each ($collection as $item) {
// update query to set order=n where id=$item[id]
n += 1
}
Any other thoughts?
Very much, definitely, please, use the 2nd method... I.E. cycle through records and update.
Quick reason for not using temp tables:
If you're using a MySQL temporary table, it is visible to the current session; which could actually be shared by multiple sessions if you are using persistent connections. If you run the script twice at the same time, it could cause some data corruption. The same thing applies to creating real tables.
What you should do is:
Retrieve all your data, or at least retrieve them in logical batches (in this case, it could be done by retrieving only rows of a particular "collection", e.g. fruits)
Order the rows (this could also have been done previously within the SQL query)
Update the rows using a counter, exactly like you have proposed

Categories