askilondz
askilondz

Reputation: 3294

Laravel whereIn with a where clause on each array item

Say I have a user object (which belongsToMany groups) and I'm doing a whereIn with an array of their respected ids like so:

whereIn('user_id', $group->users->modelKeys())

I need to, however, set a condition where I only pull data from each array item based on a condition of the group_user pivot table, "created_at" (which is basically a timestamp of when that user was added to the group).

So I need something like this:

whereIn('user_id', $group->users->modelKeys())->whereRaw('visits.created_at > group_user.created_at')

That doesn't work though because it's not doing the whereRaw for each array item but it's doing it once for the query as a whole. I might need to do something like a nested whereIn but not sure if that'll solve it either. Thoughts?

My full query as it is now:

     $ids = $group->users->modelKeys();

     return DB::table('visits')->whereIn('user_id', function($query) use ($ids) {
        $query->select('user_id')->from('group_user')->whereIn('group_user.user_id', $ids)->whereRaw('visits.created_at > group_user.created_at');
    })->sum("views");

Ok got it to work using nested loops instead:

    $visits = DB::table('visits')->whereIn('user_id', $group->users->modelKeys())->get();

    $sum = 0;

    foreach($group->users as $user) {

        foreach($visits as $visit) {

            if($visit->user_id == $user->id) {

                if($visit->created_at >= $user->pivot->created_at) {
                    $sum += $visit->views;
                }
            }
        }

    }

    return $sum;

Would still like to see if it's possible to do it in a single query, no array looping.

Upvotes: 0

Views: 7881

Answers (3)

askilondz
askilondz

Reputation: 3294

Solved it! The foreach loop approach was making calls take waaaay too long. Some queries had over 100k records returning (that's a lot to loop through) causing the server to hang up. The answer is in part a big help from Dharmesh Patel with his 3rd edit approach. The only thing I had to do differently was add a where clause for the group_id.

Here's the final query (returns that 100k results query in milliseconds)

    //Eager loading. Has overhead for large queries
    //$ids = $group->users->modelKeys();

    //No eager loading. More efficient
    $ids = DB::table('group_user')->where('group_id', $group->id)->lists('user_id');

    return DB::table('visits')->join('group_user', function ($query) use ($ids) {
        $query->on('visits.user_id', '=', 'group_user.user_id')->on('visits.created_at', '>=', 'group_user.created_at');
    })->whereIn('group_user.user_id', $ids)->where('group_id', $group->id)->sum('views');

Upvotes: 2

Dharmesh Patel
Dharmesh Patel

Reputation: 1891

I guess you need to use JOINS for this query, following code may take you in right direction:

$ids = $group->users->modelKeys();

return DB::table('visits')->join('group_user', function ($query) use ($ids) {
    $query->on('visits.user_id', '=', 'group_user.user_id')
        ->whereIn('group_user.user_id', $ids)
        ->whereRaw('visits.created_at > group_user.created_at');
})->sum("views");

EDIT

$ids = $group->users->modelKeys();

return DB::table('visits')->join('group_user', function ($query) use ($ids) {
    $query->on('visits.user_id', '=', 'group_user.user_id');
})->whereIn('group_user.user_id', $ids)
   ->whereRaw('visits.created_at > group_user.created_at')->sum("views");

EDIT

$ids = $group->users->modelKeys();

return DB::table('visits')->join('group_user', function ($query) use ($ids) {
    $query->on('visits.user_id', '=', 'group_user.id') // group_user.id from group_user.user_id as per the loop
          ->on('visits.created_at', '>=', 'group_user.created_at');
})->whereIn('group_user.user_id', $ids)
   ->sum("views");

Upvotes: 1

Raphael Rafatpanah
Raphael Rafatpanah

Reputation: 19967

Have you considered using a foreach?

$users = whereIn('user_id', $group->users->modelKeys());

foreach ($users as $user) {
  // do your comparison here
}

Upvotes: 1

Related Questions