Laravel 5: Grabbing a single record from a query using `take` - laravel

Right now, I am using Eloquent like this: MobileAppUsers::where('store', '=', 'store_name')->first(); It turns out I don't need to check the store_name because the entire table is within that store's database, so I just want the single record that will be there (there will only be 1).
Without changing any other logic, would the equivalent of MobileAppUsers::where('store', '=', 'store_name')->first(); (ignoring the store_name) be :
MobileAppUsers::take(1)->get(); ?

you can use this
MobileAppUsers::first();
Regards, I hope this help you

Related

Eloquent ORM get latest items query

I am trying to do get all the latest items and sort by id descending (i.e. get all items that were just added with a limit and offset).
So I did this:
$products = Product::all()
->slice($request->get('offset'))
->take($request->get('limit'))
->sortByDesc('id')
->toBase();
However it seems when I have more that that limit, then I dont have the right order. It gets me say 10 products but not sorted corrected. Any idea how to do this with Eloquent ORM?
You are probably intending to have the database handle the offset and skipping and ordering instead of pulling all the possible records then taking only what you want, then sorting them ... if you were going to do it your way you would need to sort before you skip and take, by the way.
Using the database to the the filtering and ordering:
$products = Product::skip($request->input('offset'))
->take($request->input('limit'))
->orderBy('id', 'desc')
->get();
I think the issue is you're using ::all() first, which returns all Product instances in a Collection, then using collection methods. Since these methods act in order of usage, you're slicing and offsetting before sorting, so you'll get the same products each time. Use proper Builder syntax to handle this properly and more efficiently:
$products = Product::offset($request->input("offset"))
->limit($request->input("limit"))
->orderBy("id", "DESC")
->get();
Because this is a Builder instance, the query will be compiled and executed according to your Database's grammar logic, and in a single query. There's nothing wrong in using Collection logic, you'd simply have to use the correct order of methods (sortByDesc() first, then slice(), then take()), but this is incredibly inefficient as you have to handle every Product in your database.

Forcing Partition Query Using Laravel

Hi I am currently writing a query where I would like to force the partition that the query uses. I know this code is working in MySQL but I don't know how I would write this using laravel.
This is the MySQL code I would use to force the partition
PARTITION (p46)
I have tried writing the following in Laravel but it doesn't seem to be working
->raw('PARTITION (p46)')
I'm not sure if raw is even a method you can use in laravel which is why it probably doesn't work.
I am using this partition enforcement instead of using the below code, it makes my queries much faster.
->where('venue_id', 46)
My table is partition using HASH(venue_id) and I have tried using the MySQL code and that is working perfectly.
Thank you in advance if you have a solution for this, I haven't been able to find anywhere which explains how to do this.
Here is my full laravel query to give you some context:
$bodyVisitors->selectRaw('SUM(visitors_new) AS new, SUM(visitors_total) AS total')
->raw('PARTITION (p' . $venue_filter . ')')
->where('day_epoch', '>=', $body_start)
->where('day_epoch', '<', $body_end)
->get();
The ->raw() is being ignored is there anyway to make this work? I am fine if the answer is no, I will just stop using laravel to write those queries.
I also suffer the partition problem for whole day...
The way I solve is
select the max timestamp and max ID for T1 then left join it to the T2 on T1.timestamp and ID
Hope that my suggestion would give a some help...
I am still writing the eloquent script almost done :'(
Try like this in your Eloquent Model:
$table = $this->getConnection()->getTablePrefix() . $this->getTable();
$table .= ' PARTITION ({your partition})';
$this->newQuery()->from($table)->where()->get();
that will be making a query like this:
select * from table PARTITION (xxxxxx) where
Try adding this scope
{
$query->from($partition);
}
and $partition is a name of your partition. Try $partition = 'p46' in your case

doing a where() after a get()

I'm trying to add a new feature to an existing Laravel codebase and in that codebase there's this:
$hasGAP = (new \App\Models\Policy)->where('leadID', $leadId)
->where('policystatus', '!=', 'Canceled')
->get()->where('product.name', 'GAP Insurance')->count() > 1;
So this is doing an SQL query on the table referenced by the \App\Models\Policy model. It's doing WHERE policystatus != 'Canceled' and then it's getting the result. And then it's doing a WHERE on the result? That doesn't make sense to me.
Also, product.name isn't a column in the table. Indeed, it seems like the period (.) operator would be an illegal character..
Does this code actually work and if so what is it actually doing?
The ->get() ends the query and returns the results in a collection.
The subsequent ->where(..) and ->count() are then calls on the collection.
The dot notation is widely used in Laravel for getting sub fields of arrays, objects and similar data structures (example: array_get()) and works in ->where() (on a collection) as well.
So the posted code should work. I assume the Policy belongsTo (or hasOne) a product and the dot notation is used to search by the related product name.

Laravel 4 - Find item by column

I was wondering if i could get a bit of help.
Is there any way to change the 'find' parameters to search in another column?
If i use
$test = Model::find($id)
This searches the ID field of a table, but what if i want to search by the token column instead.
Is there any way of doing that?
Cheers,
You can use:
$test = Model::where($column, '=', $value)->first()
The find method is attached to the primary key. You could maybe override it in your model, but you have other ways to achieve your goal without overriding it.

Laravel - Really struggling to understand eloquent

I'm fairly new to Laravel having come over from Codeigniter and for the most part I really like it, but I really can't get my head around Eloquent.
If I want to do a simple query like this:
SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id
I try doing something like this (with a "belongs to"):
$site = Site::with('tweeter')->find($site_id);
But now I have two queries and an IN() which isn't really needed, like so:
SELECT * FROM `site` WHERE `id` = '12' LIMIT 1
SELECT * FROM `tweeter` WHERE `id` IN ('3')
So I try and force a join like so:
$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->find($site_id);
And now I get an error like so:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous
SQL: SELECT * FROM `site` INNER JOIN `tweeter` ON `tweeter`.`id` = `site.tweeter_id` WHERE `id` = ? LIMIT 1
Bindings: array (
0 => 12,
)
It's obvious where the error is, the where needs to use something like "site.id = ?". But I can't see anyway to make this happen?
So i'm just stuck going back to fluent and using:
DB::table('site')->join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id','=',$site_id)->first()
I guess it's not a massive problem. I would just really like to understand eloquent. I can't help but feel that i'm getting it massively wrong and misunderstanding how it works. Am I missing something? Or does it really have to be used in a very specific way?
I guess my real question is: Is there anyway to make the query I want to make using Eloquent?
I actually find this behaviour advantageous. Consider this (I'll modify your example). So we have many sites and each has many tweeters. Each site has a lot of info in the DB: many columns, some of them text columns with lots of text / data.
You do the query your way:
SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id
There are two downsides:
You get lots of redundant data. Each row you get for a tweeter of the same site will have the same site data that you only need once so the communication between PHP and your DB takes longer.
How do you do foreach (tweeter_of_this_site)? I'm guessing you display all the sites in some kind of list and then inside each site you display all of it's tweeters. You'll have to program some custom logic to do that.
Using the ORM approach solves both these issues: it only gets the site data once and it allows you to do this:
foreach ($sites as $site) {
foreach($site->tweeters as $tweeter) {}
}
What I'm also saying is: don't fight it! I used to be the one that said: why would I ever use an ORM, I can code my own SQL, thank you. Now I'm using it in Laravel and it's great!
You can always think of Eloquent as an extension of Fluent.
The problem you're running into is caused by the find() command. It uses id without a table name, which becomes ambiguous.
It's a documented issue: https://github.com/laravel/laravel/issues/1050
To create the command you are seeking, you can do this:
$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id', '=', $site_id)->first($fields);
Of course, your syntax with join()->find() is correct once that issue fix is adopted.

Resources