Eloquent:最新相关模型符合许可的模型范围
Eloquent: Scope for Model where latest related Model meets permission
我有一个模型产品,其中包含许多模型价格。
每天都有不同的产品价格。
现在我正在尝试创建一个范围,为我提供最新价格介于两个值之间的所有产品。
我用 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 列?
对于以后的价格,您可以使用数据库临时列,也可以使用 redis。但我推荐临时专栏。
第一个解决方案:临时 Table
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");
在此示例中,每个任务都有很多作业,您可以查询数据库以创建临时 table 并从 jobs
;
中获取 last_job
第二种解决方案:使用缓存服务器
DBMS temp table 很快,但您可以通过缓存服务器(例如 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 的数据库 table 并使用 [=52= 每天更新它] 安排如下:
在 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 Table.
并使用 join 定义范围,使用这个漂亮的包: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);
}
我有一个模型产品,其中包含许多模型价格。 每天都有不同的产品价格。
现在我正在尝试创建一个范围,为我提供最新价格介于两个值之间的所有产品。
我用 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 列?
对于以后的价格,您可以使用数据库临时列,也可以使用 redis。但我推荐临时专栏。
第一个解决方案:临时 Table
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");
在此示例中,每个任务都有很多作业,您可以查询数据库以创建临时 table 并从 jobs
;
last_job
第二种解决方案:使用缓存服务器
DBMS temp table 很快,但您可以通过缓存服务器(例如 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 的数据库 table 并使用 [=52= 每天更新它] 安排如下:
在 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 Table.
并使用 join 定义范围,使用这个漂亮的包: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);
}