Laravel - получить одно значение из красноречивой модели для импорта с данными в виде одного файла

У меня есть модель PRODUCT, которая имеет отношения один ко многим с моделью REVIEW. в таблице REVIEW есть столбец «скорость», и я хочу, чтобы средняя ставка из таблицы REVIEW была связана с данными PRODUCT, когда я извлекаю все продукты. Я попытался создать метод в модели PRODUCT для вызова 'rate' в команде ::with(), чтобы сделать это, и это код:

class Product extends Model{
public function rate(){
    return $this->hasMany('App\Review')->select('rate')->avg('rate');
}

в контроллере:

return Product::with('rate')->get();

но я продолжаю заканчивать с ошибками ..

так это можно сделать в модели или есть другой способ? Любая помощь приветствуется.

Добро пожаловать в StackOverflow! Пожалуйста, опубликуйте здесь любые связанные ошибки, чтобы мы могли продолжить проверку. Спасибо.

1000Nettles 22.02.2019 20:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
2
1
537
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете попробовать что-то вроде этого:

class Product extends Model{

    public function review(){
        return $this->hasMany('App\Review');
    }

    public function rate(){
        return $this->review()->avg('rate'); // chain your query here
    }

}

то вы можете получить к нему доступ, например:

$product = Product::find(1);
dd($product->rate()->get());

Laravel использует множество магических методов. Вы можете подключиться к этому с чем-то вроде этого.

class Product extends Model{
    public function Reviews(){
        return $this->hasMany(Review::class);
    }
    public functions getRatingAttribute(){
        return $this->Reviews->avg('rate');
    }
}

то вы можете получить доступ вот так...

Product::find(1)->rating;
Ответ принят как подходящий

В большинстве случаев лучше, чтобы ваши методы, определяющие отношения, были как можно более простыми.

public function reviews(){

    return $this->hasMany('App\Review');
}

Теперь вы можете использовать это соотношение для получения скорости. Вы можете сделать это разными способами:

1. Добавляем его как добавленное свойство:

Вы можете добавить свойство, которое не является столбцом в вашей модели, в качестве добавленного свойства.

protected $appends = ['rate'];

а затем есть функция для присвоения значения:

public functions getRateAttribute(){

     return $this->reviews->avg('rate') ?? 0;
}

Проблема в том, что добавленное свойство, как следует из названия, всегда добавляется к экземпляру модели.

Итак, если вы просто сделаете следующее:

$product = Product::first();

Даже если вам не нужен рейт, у laravel все равно будет готов $product->rate для вас и из-за чего он будет делать средний запрос.

2. Имея это как метод:

Это вариант, когда вы можете просто создать его как метод:

public functions getRate(){

     return $this->reviews->avg('rate') ?? 0;
}

Преимущество этого в том, что вы можете использовать это, когда вам нужно. Это избавляет от множества ненужных запросов, которые выполняет функция добавленного свойства, даже если она вам не нужна.

Затем это можно использовать:

$product = Product::first();

// The query fo average will be done below only when you call `getRate` on `$product`

$rate = $product->getRate();

Я бы сделал это как вариант 2, если бы у меня был выбор.

Также обратите внимание на Laravel avg('column_name):

  • Он дает null, когда нет данных
  • Это дает значение что-то вроде 0.0, если вы усредняете нечисловой столбец
  • Дает действительное значение в формате 3.9265, если присутствует значение, превышающее 2 десятичных знака (в основном 4)

Таким образом, вы можете иметь свою функцию соответственно.

Все вышеупомянутые решения приводят к проблеме N+1. Вы можете попробовать ниже, чтобы добиться быстрой загрузки

namespace App;
use DB;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class Product extends Model
{
    public function reviews()
    {
        return $this->hasMany('\App\Review');
    }

    public function ScopeAverageRating(Builder $query){
        return $query->withCount(['reviews as average_rating' => function ($query) {
            $query->select(DB::raw("avg(rate)"));
        }]);
    }

}

Затем в вашем контроллере вы можете использовать App\Product::AverageRating(), он вернет вам коллекцию, которую можно повторить, чтобы получить Average_rating.

Другие вопросы по теме