【问题标题】:Querying and filtering on calculated column with eager loading in Eloquent在 Eloquent 中使用预加载对计算列进行查询和过滤
【发布时间】:2014-11-11 11:25:44
【问题描述】:

我目前有三个模型,它们的 Eloquent 查询使用预加载。我的模型有这些关系:

class Template extends Eloquent {
    public function user() {
        return $this->belongsTo('User');
    }
}

class User extends Eloquent implements UserInterface, RemindableInterface {
    public function profiles() {
        return $this->hasMany('Profile');
    }
    public function templates() {
        return $this->hasMany('Template');
    }
}

class Profile extends Eloquent {
    public function user() {
        return $this->belongsTo('User');
    }
}

我的工作查询如下所示:

$templates = Template::with('user', 'user.profiles')
    ->where('public', '=', true)
    ->whereIn('type', $search_types)
    ->where('user_id', '!=', $user->id)
    ->paginate(8);

这似乎工作得很好,但我需要再添加一件事,这对我来说很难做到正确。我需要使用user 表中现有的latlong 列来更改此查询以考虑模板用户与当前用户的距离。我只希望查询返回其用户在当前用户 25 英里范围内的模板(理想情况下按距离排序,但该部分是可选的)。

我尝试向用户关系添加自定义计算列,如下所示:

$templates = Template::with(array('user' => function($query) use($user) {
        $query->select('*')->selectRaw('(3959 * acos(cos(radians(?)) * cos(radians(lat)) * cos(radians(long) - radians(?)) + sin(radians(?)) * sin(radians(lat)))) AS distance', array($user->lat, $user->long, $user->lat));
    }, 'user.profiles' => function($query) {
        $query
    }))
    ->where('public', '=', true)
    ->whereIn('type', $search_types)
    ->where('user_id', '!=', $user->id)
    ->having('distance', '<=', 25)
    ->orderBy('distance')
    ->paginate(8);

这不起作用,因为在预先加载时,初始查询中不存在distance 列,导致它在having 子句中失败。如果我将该部分移到匿名函数中并删除排序,它不会立即失败,但它只是忽略模板查询的距离,然后只抓取 25 英里内的相关用户,这似乎不是有帮助。

使用 Eloquent 获取我想要的数据的正确方法是什么?

【问题讨论】:

  • 您的情况有什么解决方案吗?与我的相似,如果有一些想法来使用一些内置的 laravel 技术,那就太好了。

标签: laravel eloquent


【解决方案1】:

我最终得到了以下结果(没有可选的排序),这似乎工作得很好:

$templates = Template::with('user', 'user.profiles')
    ->where('public', '=', true)
    ->whereIn('type', $search_types)
    ->where('user_id', '!=', $user->id)
    ->whereHas('user', function($query) use($user, $distance) {
        $query->whereRaw('(3959 * acos(cos(radians(?)) * cos(radians(location_lat)) * cos(radians(location_long) - radians(?)) + sin(radians(?)) * sin(radians(location_lat)))) <= ?', array($user->location_lat, $user->location_long, $user->location_lat, $distance));
    })
    ->paginate(8);

【讨论】:

  • 您知道一种将“距离”作为属性实际返回给每个返回用户的方法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2021-02-24
  • 2019-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多