I have this table store_photos and I am trying to get the photos with complete raffle_date_id upto 12 and then group them by user_id. The query works but then it still generate collection even if its not complete upto 12. How can I achieve this using whereIn() or other similar eloquent?
public function collection(): Collection
{
$months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
return StorePhoto::with('user.location')
->whereIn('raffle_date_id', $months)
->groupBy('user_id')
->get();
}
You can try constructing the RAW SQL query, to find what you are trying to achieve.
Then you can slowly build your way in Laravel.
You can try to find those users who have count of 12 (i.e. have 12 records = have 12 months). Then you can get only those users.
SELECT user_id FROM store_photos AS sp
GROUP BY sp.user_id
HAVING COUNT(sp.user_id) = 12;
Then in Laravel you can
DB::table('store_photos')
->groupBy('user_id')
->having(DB::raw('count(user_id)'), '=', 12)
->select('user_id');
*I do not know that much about your app and its business logic / requirement. But you get the idea :)
Related
In laravel 9 I got last value in related CurrencyHistory table
$currencies = Currency
::getByActive(true)
->withCount('currencyHistories')
->with('latestCurrencyHistory')
->orderBy('ordering', 'asc')
->get();
In model app/Models/Currency.php I have :
public function latestCurrencyHistory()
{
return $this->hasOne('App\Models\CurrencyHistory')->latest();
}
But checking generated sql I see lines like :
SELECT *
FROM `currency_histories`
WHERE `currency_histories`.`currency_id` in (8, 13, 16, 19, 27, 30)
ORDER BY `created_at` desc
I suppose this code is raised by latestCurrencyHistory method and wonder can
I set some limit 1 condition here, as resulting data are too big.
Thanks!
Query is correct. As you eager load your relation for the collection of currencies using with method, you load currency_histories for all of your Currency models in collection.
If you dump the result, you will have currencies with IDs: 8, 13, 16, 19, 27, 30 and one latestCurrencyHistory (if present) for each.
I am trying to filter by rating. It can be for a record from 1 to 5. From the frontend comes a string, for example "1,3,5", which means - show all entries with a rating of 1, 3 and 5 at once.
$reviews = $this->data['sort_by'] = Review::query()
->where('rating', $data['rating'])
->get()
This is how I can get with only one value, but I need several at once. Also, the difficulty is that there can be not only "1, 3, 5", but also any other combinations, for example, "1, 4, 3" or "3,5,2"
If someone means how to compose a request before the get () method, it would be ideal so that all the work is at the database level and the server does not have to filter the collection, but in any case, I will be very happy with any solution where there will be only one request to the database data. Of course, I can make a separate request for each rating and glue them later, but that would be bad practice.
explode the posted rating so it becomes an array and use whereIn() instead of where():
$reviews = $this->data['sort_by'] = Review::query()
->whereIn('rating', explode(',', $data['rating']))
->get()
i want to select several random rows from database, something like this
select * from table order by rand limit 10
how to do it in Laravel eloquent model?
Do something like this:
User::orderBy(DB::raw('RAND()'))->take(10)->get();
It's simple than it looks like, you just have to use the suffle() collections method.
The shuffle method randomly shuffles the items in the collection:
$collection = collect([1, 2, 3, 4, 5]);
$shuffled = $collection->shuffle();
$shuffled->all();
// [3, 2, 5, 1, 4] // (generated randomly)
For further methods and info you should check the laravel eloquent docs, there are methods almost for everything.
Cheers.
I have the following
"end_time" represents datetime in unix format
$vouchers = DB::table('deals_sales')
->whereIn('status', [0, 1])
->where('end_time', '>=', strtotime("+5 day"))
->get();
What I'm trying to achieve is get all results that are going to end between now and next 5 days, but with my query I get even those that are going to expire in 10 days.
I just don't see the logic on how to get it.
Any ideas?
Thanks
Since you're using integer timestamps you might be looking for whereBetween. Try the follwing:
$vouchers = DB::table('deals_sales')
->whereIn('status', [0, 1])
->whereBetween('end_time', [time(), strtotime("+5 day")])
->get();
This will get you the entries that have end_time between now and the next 5 days.
Two seemingly identical queries (as far as a newbie like me can tell, but the first is faster overall in the partial template rendering time (nothing else changed but the ids statement). Also, when testing through rails console, the latter will visibly run a query, the former will not. I do not understand why - and why the first statement is a few ms faster than the second - though I can guess it is due to the shorter method chaining to get the same result.
UPDATE: My bad. They are not running the same query, but it still is interesting how a select on all columns is faster than a select on one column. Maybe it is a negligible difference compared to the method chaining though.
ids = current_user.activities.map(&:person_id).reverse
SELECT "activities".* FROM "activities" WHERE "activities"."user_id" = 1
SELECT "people".* FROM "people" WHERE "people"."id" IN (1, 4, 12, 15, 3, 14, 17, 10, 5, 6) Rendered activities/_activities.html.haml (7.4ms)
ids = current_user.activities.order('id DESC').select{person_id}.map(&:person_id)
SELECT "activities"."person_id" FROM "activities" WHERE "activities"."user_id" = 1 ORDER BY id DESC
SELECT "people".* FROM "people" WHERE "people"."id" IN (1, 4, 12, 15, 3, 14, 17, 10, 5, 6) Rendered activities/_activities.html.haml (10.3ms)
The purpose of the statement is to retrieve the foreign key reference to people in the order in which they appeared in the activities table, (on its PK).
Note: I use Squeel for SQL.
In the first query, you've chained .map and .reverse, while in the second query, you've used .order('id DESC') .select(person_id) which were unnecessary, if you added .reverse