【问题标题】:Eloquent: Scope for Model where latest related Model meets permissionEloquent:最新相关模型符合许可的模型范围
【发布时间】:2021-03-20 01:58:32
【问题描述】:

我有一个具有许多模型价格的模型产品。 每天都有不同的产品价格。

现在我正在尝试创建一个范围,为我提供最新价格介于两个值之间的所有产品。

我用 whereHas 查询试过这个:

public function scopePriceBetween($query, ...$priceRange) {
  return $query->whereHas('price', function ($query) use ($priceRange) {
     $query->latestPrice()->whereBetween('price', $priceRange); 
  })
}

价格模型的范围

public function scopeLatestPrice($query) {
  return $query->latest('date')->limit(1);
}

但这会给我所有价格介于该范围之间的产品,而不仅仅是最新价格。

有没有办法在 eloquent 中以可接受的性能做到这一点,还是我需要在我的产品模型中添加 latest_price 列?

【问题讨论】:

  • 您如何指定最新价格?你们有不同的产品价格吗?如果是的话,你是如何讲述这些故事的?
  • 投稿我的回答让你满意吗?我认为在这种情况下使用范围不是一个好主意
  • 我正在使用范围,因为我使用的包可以通过查询字符串进行过滤,然后将其转换为范围。 @PrafullaKumarSahu 价格是他们自己的模型,它们存储在一张桌子上,每天的价格。所以是的,一种产品有不同的价格。
  • 所以我认为您可以使用我提到的一种方法来实现 last_price。并使用范围查询last_price。
  • 我要在范围内创建临时表吗?

标签: laravel eloquent laravel-query-builder


【解决方案1】:

对于以后的价格,您可以使用数据库临时列,也可以使用 redis。但我推荐临时列。

第一个解决方案:临时表

DB::statement("CREATE TEMPORARY TABLE last_prices SELECT prices.* from prices join products on products.id=prices.product_id and prices.id=(select id from prices where prices.product_id=products.id and `prices`.`deleted_at` is null order by `id` desc limit 1);");
        $query = Product::select("products.*")
                 ->join("last_prices", "products.id", "last_prices.product_id");
        

在这个例子中,每个任务都有很多作业,你可以查询数据库做一个临时表并从jobs获取last_job

第二种解决方案:使用缓存服务器

DBMS 临时表速度很快,但您可以通过缓存服务器(例如 redis)获得性能。

您可以通过 product_id 将每个产品的最新价格存储在缓存服务器中:

  public function getLastPriceAttribute(){
    
    //cache for an hour
    $p_id = $this->id;
    return  Cache::tags(['product'])->remember($this->id, 60*60, function () uses ($p_id) {
            return Price::where('product_id', $p_id)
                ->latest()
                ->first();
        });  
}

第三种解决方案:

如果您的价格每天更新,并且您没有或不想使用缓存服务器,您可以创建一个名为 last_prices 的数据库表,并使用 laravel 计划每天更新它,如下所示:

App\Console\Kernel.php

//suggestion has not tested
protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
            $updateValues = array();
            
            foreach( Product::all() as $product){
               array_push($updateValues , array(
                   "product_id" => product->id,
                   "price_value" => 
                   Price::where('product_id',$product->id)
                   ->latest()
                   ->first()->price_value;
                   ));
             }
        LastPrices::updateOrInsert($updateValues);
        })->dailyAt("05:30");        }

更新

为此:

Product::latestPriceBetween([100,200])->category('electronics');

您可以制作建议的第三个解决方案来创建 Last_price 表。

并通过连接定义范围,使用这个不错的包:https://github.com/fico7489/laravel-eloquent-join

看起来像这样:

public function scopePriceBetween($query, ...$priceRange) {
  return $query->join("last_prices","last_prices.product_id","products.id")->whereBetween('last_prices.value', $priceRange);
}

【讨论】:

  • 我不会为每个会话创建一个临时表吗?该逻辑用于我想过滤某个范围内的价格的 api 端点。
猜你喜欢
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-23
相关资源
最近更新 更多