Eloquent deleting more records than intended? - laravel

Post::whereReplyTo($request->input('reply_to'))
->orderBy('updated_at', 'desc')
->offset(Config::PAGE_SIZE * Config::MAX_PAGES)
->take(1024)
->delete();
I intend to fire this when post count reaches 4 in order to maintain a maximum of 4 posts, in this case.
Problem is it deletes ALL posts, not only those that I intended to delete
I'm becoming frustrated, why is this happening? theres no error, and I toSql'd the query and nothing is wrong, the selction part is correct, I tried it, so why is it deleting ALL posts???

Well, if your research is correct, you should still be able to do it with two steps:
$delete_posts = Post::select('id')->whereReplyTo($request->input('reply_to'))
->orderBy('updated_at', 'desc')
->offset(Config::PAGE_SIZE * Config::MAX_PAGES)
->take(1024)
->get()->toArray();
Post::whereIn('id', $delete_posts)->delete();

I think I'm on to something
I appended a listener to log the last query after running my Delete
the result was:
delete from `a2_posts` where `reply_to` = ? order by `updated_at` desc limit 1024
so where is my offset? I googled around and I think you cant use offset + delete.
retarded? yes, very much so.
This is why I like Mongo better.
It makes more sense.
Source: Mysql delete statement with limit
so what I think I'll do is query, then iterate, then delete.
SQL is pure genius sometimes I swear to God.

Related

Laravel - Shuffle Merge and Paginate Collection

I am struggling with a pretty difficult thing and hope you can help me out.
Right now I've got the following:
$ads = Ad::where('status', 1)
->whereIn('ad_type', [1, 2, 3])
->where('expire_at', '>', date('Y-m-d H:i:s'))
->where('special_ad', 'standard_ad')
->orderByRaw(DB::raw("FIELD(ad_type,2,3,1)"));
Info:
This is working because it is an Eloquent Collection and I can Paginate this (needed for my Infinite Scroll)
But now I want to shuffle the ad_types in itself, meaning:
ad_type 1 could have, let's say, 30 entries. They will all be returned in the usual order. I want to shuffle those 30 every time I run this query.
I thought about doing ->toArray(); but then again, no pagination (Pagination only works on Eloquent Queries right?)
Then I thought, hey, let's merge this.
But as soon as I did that, the returned collection is no longer an Eloquent Collection but a Support Collection (right? I am not 100% sure it is a Support Collection) thus the Pagination does not work anymore.
I read upon many posts as how to solve this problem, and figured out one solution may be to "create my own paginator instance"
But heck, I am not that good yet. I do really not know, even after studying the laravel documentation, how to create my own paginator.
Important Infos you might need:
Using Laravel 5.2
$ads are dynamical, meaning depending on the case, the requests sent with Ajax, the query might differ at a later point (something might get included).
Thank you very much for your time reading this and hopefully, you can help me and future readers by solving this particular problem.
Greetings, and a great weekend to all of you.
Firstly just to note:
Pagination does not only work for database queries. You can manually paginate using LengthAwarePaginator but manually is the keyword here. The query builder (not Eloquent) can do it automatically for you using paginate.
You can "shuffle" the results by doing something like
$ads = Ad::where('status', 1)
->whereIn('ad_type', [1, 2, 3])
->where('expire_at', '>', date('Y-m-d H:i:s'))
->where('special_ad', 'standard_ad')
->orderByRaw("FIELD(ad_type,2,3,1)")
->orderByRaw("RAND()");
This will order by the ad_type field first and order by a random number (different for every row) as a secondary sort.

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

Delete query builder in laravel/eloquent using slim3 returning integer 0

I am using slim3 eloqent/laravel and am trying to build a query to delete an entry from the database using multiple where clauses.
According to laravel's documentation this query should delete correctly;
$deleteGalleryItem = Home_Page::where("ul_id",$ul)
->where("ul_update_no",$ul_update_no)
->delete();
var_dump($deleteGalleryItem);
die();
I also tried;
$deleteGalleryItem = Home_Page::where("ul_id","=",$ul)
->where("ul_update_no","=",$ul_update_no)
->delete();
var_dump($deleteGalleryItem);
die();
However each time I run the var_dump I get returned integer 0
Is this the correct way to structure a mysql delete statement in eloquent/laravel in slim3?
Or should I first select the data then delete?
There is nothing wrong with the way you've constructed your query.
The number returned is how many rows were removed with that query, so the reason you'll be getting 0 is simply because you didn't have any rows in the database with those constraints.
Hope this Helps!

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.

how to properly order_by(time) in codeigniter

How do I do the order_by part in codeigniter?
SELECT <field> FROM <table> ORDER BY STR_TO_DATE( <field>, '%H:%i' ) DESC LIMIT 0 , 30
Tried this but it takes "'%H:%i')" as the field name.
$this->db->order_by("STR_TO_DATE(".$field.", '%H:%i')", $order);
The field is a varchar and the query I posted returns the result that I want but I don't know how to do it in codeigniter
I don't think you can do that in CodeIgniter in version 2.1.0. As Madmartigan put it, the comma trigger CI to wrap the wrong part in the backticks and thus giving the mysql error. I think there is no point digging into active record on the order_by function to find a workaround than a real fix for this to work. I check into the upstream and apparently, they have something which is interesting, you might want to keep an eye when is that released.
I didn't spend more time to find workaround in active record order_by but resort to this alternative which seem to work fine. Consider the following?
$sql = "SELECT <field> FROM <table> ORDER BY STR_TO_DATE(?, '%H:%i') desc LIMIT 0, 30";
$this->db->query($sql, array('19:20'));

Resources