【问题标题】:I have a working laravel select query. how do i add filters?我有一个有效的 laravel 选择查询。如何添加过滤器?
【发布时间】:2017-12-18 09:09:37
【问题描述】:

大家好,最近怎么样?在此先感谢。
我在 laravel 模型中编写了一个工作函数,它进行地理搜索并返回按距离搜索的顺序。效果很好。

 public static function searchByDistance($distance, $unit)
{
    //spatial queries
   // $circle_radius = 6371; 
    $circle_radius = 3959; 
    $max_distance = $distance;
    $lat = Auth::user()->getLoc()->latitude;
    $lng = Auth::user()->getLoc()->longitude;
    //get all nearby places
     $nearbyusers = DB::select(
           'SELECT * FROM
                (SELECT users.id, users.country, places.name, places.state_code, places.latitude, places.longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
                cos(radians(longitude) - radians(' . $lng . ')) +
                sin(radians(' . $lat . ')) * sin(radians(latitude))))
                AS distance
                FROM users
                LEFT JOIN places ON users.suburb=places.name) AS distances
            WHERE distance < ' . $max_distance . '
            ORDER BY distance;
     ');        
   $nearbyusers = (object)$nearbyusers;
    return $nearbyusers;
}

但是我有一个问题。我想调用该函数,返回一个查询并继续对它进行add -&gt;where() 操作,直到我准备好使用get() 并返回结果。

我不能使用where() or get(),我知道为什么。它的格式不正确。 有没有人可以帮助我修改/更改函数,以便在我返回 $nearbyusers 值后添加更多过滤器?

干杯

【问题讨论】:

  • 您正在使用哪个 ORM / 查询构建器(如果有)?
  • @ClémentMalet 看起来很有口才。
  • 您想在上述查询或任何其他查询上添加where() or get() 吗?
  • 我用的是雄辩的。我想添加 where()s 和最后一个 get() 原因是我可以通过上述查询按距离顺序进行搜索,我很兴奋我破解了它!但是我希望能够在此之外添加更多过滤器,例如年龄之间等
  • 有什么方法可以帮我将这个原始查询转换为 ORM eloquent 吗?我一直在尝试不成功

标签: php mysql laravel geolocation xampp


【解决方案1】:

看看official documentation for raw expressions 我想这就是你要找的。无论如何,您必须将原始查询更改为“构建”查询,如下所示:

$nearbyusersquery = DB::table('users')
    ->select(DB::RAW('SELECT users.id, users.country, places.name, places.state_code, places.latitude, places.longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
            cos(radians(longitude) - radians(' . $lng . ')) +
            sin(radians(' . $lat . ')) * sin(radians(latitude))))
            AS distance'))
    ->leftJoin('places', 'users.suburb', '=', 'places.name')
    ->where('distance', '<', $max_distance)
    ->orderBy('distance');      

return $nearbyusersquery

这样,您的方法将返回一个Builder 对象,该对象可以与其他语句链接。

【讨论】:

  • 试过因为某种原因说 Parse error: syntax error, unexpected ':', expecting ',' or ')'
  • 我的错我写的是select(DB:raw('...')而不是select(DB:raw('...'))
  • @happinin 我强烈建议您查看社区常见问题解答和帮助中心 (meta.stackexchange.com/questions/7931/…),了解此处的预期指南。
【解决方案2】:

您将希望了解底层的 Fluent 查询构建器系统。就目前而言,您的查询是独立的。这个特定的人也可能需要保持独立。

为了以您想要的方式连接到 Fluent,您需要传入查询(这应该会自动解析),添加到它,然后返回查询。就您当前的功能而言,这可能需要一种与您所拥有的完全不同的方法(尽管您所拥有的对于您想要结束的查询来说是一个很好的模型)。

查看the docs about query scopes,它可能正在解决您尝试如何集成它的问题。另外,请查看代码本身,such as this one for the JoinClause function,以了解如何构建代码。

基本元素是您需要获取并返回查询对象。这意味着它不能是静态方法(它需要对象实例),并且根据您采用的方法,您将返回传入的 $query 对象(作用域)或 $this(它们的实例模型对象本身)。

您需要想办法将您的查询封装到您需要的部分中。可能是这样的:

public function byDistance($distance, $unit) {
    $lat = Auth::user()->getLoc()->latitude;
    $lng = Auth::user()->getLoc()->longitude;

    return $this->join(DB::select('SELECT users.id, users.country, places.name, places.state_code, places.latitude, places.longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
            cos(radians(longitude) - radians(' . $lng . ')) +
            sin(radians(' . $lat . ')) * sin(radians(latitude)))
            AS distance'), 
         'users.id', 'distance.user_id = users.id')
    ->leftJoin('places', 'users.suburb = places.name')
    ->where('distance', '<', $distance)
    ->orderBy('distance');
}

请注意,查询构建部分中缺少实际的select(尽管有嵌套选择),并且缺少任何类型的实际获取。它的作用是添加到当前查询中,然后在最终调用 get 或其他 fetch 函数时构建该查询。这为您提供了一个较大查询的离散段,然后您可以在调用它时添加它。

【讨论】:

  • 谢谢,看起来很有帮助。但是我试过了,它不起作用。我收到此错误:解析错误:语法错误,意外':',期待','或')',我无法弄清楚错误在哪里。不应该有语法错误吗?它还查询两个表。如果这很重要。一个是用户,一个是地方,但我想按距离顺序从这些地方返回用户
  • 肖纳。您的函数有语法错误。我真的可以请一个直接的解决方案吗?我想要的只是有效的东西。我以后可以看书。请。
  • StackOverflow 不是为您完成工作的地方,主要是因为我们对您的项目没有您所做的洞察力。您将必须弄清楚您的特定案例的确切细节,这里的答案只会引导您朝着正确的方向前进。
  • 你的 sql 中有语法错误。所以这目前把我带到了一个不好的方向。 SQLSTATE[42000]:语法错误或访问冲突:1064 您的 SQL 语法有错误;检查与您的 MariaDB 服务器版本相对应的手册,以在第 4 行的“AS 距离”附近使用正确的语法(SQL:SELECT users.id、users.country、places.name、places.state_code、places.latitude、places.经度,(6371 * acos(cos(弧度(-34.42588)) * cos(弧度(纬度)) * cos(弧度(经度) - 弧度(150.89982)) + sin(弧度(-34.42588)) * sin(弧度(纬度)))AS距离)
  • 我所做的只是将您的查询快速转换为 Fluent 语法。我用“something like”作为开头,因为它只是一个示例,说明正确转换后会得到什么。
【解决方案3】:

你也可以用 sql 来做。例如:

   $filtr = "";
$filtr2 = "";

If (something)
 $filtr =" and field = var";

If (somethingelse)
   $filtr2 = " and field2 = other_var";

// this can be in the elloquent query
$query = "select .... 
from .... 
Where 1=1 
     $filtr
     $filtr2
";

编辑

//assuming the country Id is passed to your controller
// first initialize the filter as empty string
$countryFilter = "";

// if the country is not null or empty replace the filter
if ($country != null && $country != "")  
    $countryFilter = "and country = $countryFilter";

$nearbyusers = DB::select(
           'SELECT * FROM
                (SELECT users.id, users.country, places.name, places.state_code, places.latitude, places.longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
                cos(radians(longitude) - radians(' . $lng . ')) +
                sin(radians(' . $lat . ')) * sin(radians(latitude))))
                AS distance
                FROM users
                LEFT JOIN places ON users.suburb=places.name) AS distances
            WHERE distance < ' . $max_distance . '
            -- if no country was selected then it will just be an empty line
            $countryFilter
            ORDER BY distance;
     ');  

【讨论】:

  • 你能不能说的更彻底一点。我在这里得到了足够的对待,就像一个新手程序员一样,我似乎无法从任何人那里得到一个直接的答案。任何人都可以真正提供一个没有语法错误或......什么的工作解决方案
  • 好的,很抱歉,我不知道你要应用什么过滤器,所以我给了你一个基本的过滤器,你可以根据需要修改它
  • 如果您想在查询执行后添加过滤器,那么您可能需要一个新功能,否则您可以将过滤器添加到您已有的查询中。
  • 不确定是否是你想要的,但我编辑了答案,看看。
  • oh man SQLSTATE[42000]: 语法错误或访问冲突:1064 您的 SQL 语法有错误;查看与您的 MariaDB 服务器版本相对应的手册,了解在第 10 行的“$countryFilter ORDER BY distance”附近使用的正确语法
【解决方案4】:

又像往常一样,自己解决了。问题很简单。您所要做的就是查找与结果匹配的用户对象并将它们推送到数组中。然后返回该数组,您就可以使用这些函数了!因此,如果您想从原始查询中获取可传递的对象,这就是您要做的。再次感谢您提供有用的答案。这个问题真的很简单。最后我摆弄它来工作,而不是从互联网上得到任何答案。

//spatial queries        

                    $circle_radius = 6371;       

                   // $circle_radius = 3959; 


                $max_distance = request('distance');
                $lat = Auth::user()->getLoc()->latitude;
                $lng = Auth::user()->getLoc()->longitude;

                //get all nearby places
                 $nearbyusers = DB::select(
                       'SELECT * FROM
                            (SELECT users.id, users.country, places.name, places.state_code, places.latitude, places.longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
                            cos(radians(longitude) - radians(' . $lng . ')) +
                            sin(radians(' . $lat . ')) * sin(radians(latitude))))
                            AS distance
                            FROM users
                            LEFT JOIN places ON users.suburb=places.name) AS distances
                        WHERE distance < ' . $max_distance . '
                        ORDER BY distance;
                 ');      

                 $users = [];

                 foreach($nearbyusers as $user)
                 {
                    array_push($users, User::where('id', $user->id)->first());
                 }



               //$nearbyusers = (object)$nearbyusers;


                return Response::json( array( 
                'searchsuccess' => (String) view('members.yessearch', compact('users')) 
                ) );

【讨论】:

    猜你喜欢
    • 2017-06-15
    • 2018-02-15
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-01
    • 2016-01-18
    • 1970-01-01
    相关资源
    最近更新 更多