Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [Laravel] Eloquent poprawne zwrócenie danych
john_doe
post 10.05.2018, 14:20:36
Post #1





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

Ostrzeżenie: (0%)
-----


mam takie dwie encje

  1. public function up()
  2. {
  3. Schema::create('configurations', function (Blueprint $table) {
  4. $table->increments('id');
  5. $table->date('date_from');
  6. $table->integer('race_id');
  7. $table->timestamps();
  8. });
  9. }

w modelu mam
  1. public function parameters()
  2. {
  3. return $this->hasMany('App\Models\Parameter');
  4. }

oraz listę parametrów przypisanych do danej konfiguracji
  1. public function up()
  2. {
  3. Schema::create('parameters', function (Blueprint $table) {
  4. $table->increments('id');
  5. $table->integer('configuration_id');
  6. $table->tinyInteger('day');
  7. $table->decimal('water', 8, 3);
  8. $table->smallInteger('feed');
  9. $table->smallInteger('weight');
  10. $table->decimal('downs');
  11. $table->timestamps();


pytania z założeniami:

1. Potrzebuję wyciągnąć zsumowaną pod względem ( water, feed, weight, downs ) listę parametrów należące do configuracji o race_id in (tutaj różnie może być od jednego id po kilka) + dodatkowo jak widać mogę mieć kilka konfiguracji dla danego race_id więc potrzebują wziąć tą z najnowszą datą.

  1. $configuration = Configuration::whereIn('race_id', [1, 2])->get();


może też inaczej ,..... chciałbym osiągnąć wynik, który daje np takie zapytanie:

  1. SELECT p.[DAY], SUM(p.water), SUM(p.feed), SUM(p.weight), SUM(p.downs)
  2. FROM dbo.parameters p LEFT JOIN dbo.configurations c ON c.id = p.configuration_id
  3. INNER JOIN (
  4. SELECT race_id, MAX(date_from) AS MaxDate
  5. FROM dbo.configurations
  6. GROUP BY race_id
  7. ) tm ON c.race_id = tm.race_id AND c.date_from = tm.MaxDate
  8. WHERE c.race_id IN (1,2)
  9. GROUP BY p.[DAY]
  10. ORDER BY 4;


czyli potrzebuję wybrać najnowszą konfigurację dla danego race_id. W przypadku kilku race_id wziąć najnowszą konfigurację i dodać ja do najnowszego konfiguracji z kolejnego race_id

Chciałbym to wyciągnąc ładnie ORM i nie uzywać plain query.
Czy ktoś z Was ma pomysł?

Ten post edytował john_doe 10.05.2018, 14:37:05
Go to the top of the page
+Quote Post
r4xz
post 14.05.2018, 22:37:58
Post #2





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

Ostrzeżenie: (0%)
-----


Wyciągnięcie ostatniej konfiguracji nie powinno być trudne:

  1. $configuration = Configuration::whereIn('race_id', [1, 2])->latest('date_from')->firstOrFail();


Problem zaczyna się gdy chcesz dołączyć do tego sumy. Jeśli parametrów jest mało to możesz pobrać po prostu wszystkie rekordy i wykorzystać sumowanie dostępne na kolekcjach. Jeśli rekordów jest dużo to musisz dla każdej sumy użyć osobnego zapytania lub wykorzystać DB::raw - https://stackoverflow.com/questions/1536900...elds-in-laravel. W tym drugim przypadku wyglądałoby to mniej-więcej tak:

  1. $configuration = Configuration::with([
  2. 'parameters' => function($q) { return $q->select(DB::raw(...)); }
  3. )]->whereIn('race_id', [1, 2])->latest('date_from')->firstOrFail();


Trochę późno odpowiadam więc jeśli uporałeś się już z problemem to chętnie zobaczyłbym w jaki sposób go rozwiązałeś. Takich problemów z Eloquent jest akurat więcej i moim zdaniem mimo że wygodny, to jednak często stanowi bardzo wąskie gardło i jest jednym z gorzej przemyślanych modułów w tym frameworku.


--------------------
Go to the top of the page
+Quote Post
markonix
post 15.05.2018, 01:29:39
Post #3





Grupa: Zarejestrowani
Postów: 2 707
Pomógł: 290
Dołączył: 16.12.2008
Skąd: Śląsk

Ostrzeżenie: (0%)
-----


Cytat(r4xz @ 14.05.2018, 23:37:58 ) *
Takich problemów z Eloquent jest akurat więcej i moim zdaniem mimo że wygodny, to jednak często stanowi bardzo wąskie gardło i jest jednym z gorzej przemyślanych modułów w tym frameworku.

Na bardzoo duży system udało mi się poza jednym zapytaniem zrobić wszystko w oparciu o Eloquent. Wg mnie jest świetny, ciekawi mnie Twoja opinia. Jakieś porównania do podobnych ORMów, które wg Ciebie są lepsze?


--------------------
Go to the top of the page
+Quote Post
SmokAnalog
post 15.05.2018, 11:42:05
Post #4





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Cytat(john_doe @ 10.05.2018, 15:20:36 ) *
w modelu mam
  1. public function parameters()
  2. {
  3. return $this->hasMany('App\Models\Parameter');
  4. }

Swoją drogą pamiętaj, że jest jeszcze stała class:
  1. public function parameters()
  2. {
  3. return $this->hasMany(Parameter::class);
  4. }
Go to the top of the page
+Quote Post
r4xz
post 15.05.2018, 20:13:39
Post #5





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

Ostrzeżenie: (0%)
-----


Cytat(markonix @ 15.05.2018, 02:29:39 ) *
Na bardzoo duży system udało mi się poza jednym zapytaniem zrobić wszystko w oparciu o Eloquent. Wg mnie jest świetny, ciekawi mnie Twoja opinia. Jakieś porównania do podobnych ORMów, które wg Ciebie są lepsze?


No chociażby podstawowy problem: mamy jakiś model (nadrzędny) który załącza inne z użyciem with (model podrzędny). Teraz chciałbym wyświetlić wszystkie te dane w tabeli i mieć możliwość posortowania po kolumnie która znajduje się w modelu podrzędnym. Mogę zrobić sortowanie rekordów ale tylko w ramach danego modelu nadrzędnego. W takim prostym przypadku już musze sięgać po QueryBuilder i sklejać joiny.

ORMy mają to do siebie że w wielu przypadkach pomagają i znacznie przyśpieszają proces wytwarzania aplikacji (i za to je lubię), jednak czasami obnażają swoje wady w sposób dobitny (i wtedy zastanawiam się jakie mam alternatywy). Osobiście lubię mieć jakieś zaplecze w postaci QL jakie oferuje np. Doctrine (DQL) lub Phalcon (PHQL) z dobrym wsparciem ze strony IDE tak aby zmiany w modelu pociągały za sobą zmiany w zapytaniach (chodzi o jakieś proste zmiany nazw itp.). Gdybym miał jednak wybierać np. między Doctrine a Eloquent to nie potrafiłbym podjąć decyzji, z obu korzystam chyba równie często, każdy z nich ma swoje wady i zalety i dużo zależy od specyfiki projektu.


--------------------
Go to the top of the page
+Quote Post
SmokAnalog
post 15.05.2018, 21:39:53
Post #6





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Możesz podać konkretny przykład z tym sortowaniem? Brzmi jak coś, co da się zrobić elegancko w Eloquencie.

Poza tym jak są jakieś bardzo zagmatwane kryteria sortowania, to zawsze możesz to zrobić już na gotowej kolekcji., bez udziału bazy
Go to the top of the page
+Quote Post
r4xz
post 15.05.2018, 22:47:16
Post #7





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

Ostrzeżenie: (0%)
-----


Modele:
- Order (id, user_id, product_name, amount, ...) -> belongsTo User
- User: (id, full_name, birth_year, ...) -> hasMany Order

Cel: pobrać listę wszystkich zamówień posortowanych po np. birth_year lub product_name (w zależności od wyboru użytkownika, może to być praktycznie dowolna kolumna z jednego lub drugiego modelu). Pobranie rekordów a następnie sortowanie nie wchodzi w grę, ponieważ tabela orders zawiera kilka milionów wpisów.

Przykładowe zapytanie:
  1. Order::with('user')->orderBy(<sortowanie po birth_year>)->paginate();


--------------------
Go to the top of the page
+Quote Post
SmokAnalog
post 15.05.2018, 22:54:20
Post #8





Grupa: Zarejestrowani
Postów: 1 707
Pomógł: 266
Dołączył: 3.07.2012
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Każdy with() robi osobne zapytanie, więc posortować po tym rzeczywiście nie ma jak. Ale już join powinien dać radę. Nie ma co na siłę unikać tych joinów, one działają nie tylko z czystym query builderem, ale też z modelami. Zgadzam się jednak, że przydałaby się w Eloquencie możliwość budowania pojedynczych zapytań z relacjami i w sumie nie wiem co stało na przeszkodzie.
Go to the top of the page
+Quote Post
Pyton_000
post 15.05.2018, 23:02:44
Post #9





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

Ostrzeżenie: (0%)
-----


Zawsze można użyć QueryBuildera. Tak samo w doctrine nie da się wszystkiego wyklepać i wtedy wchodzą bardziej czyste rzeczy.
Go to the top of the page
+Quote Post
markonix
post 16.05.2018, 01:08:52
Post #10





Grupa: Zarejestrowani
Postów: 2 707
Pomógł: 290
Dołączył: 16.12.2008
Skąd: Śląsk

Ostrzeżenie: (0%)
-----


Albo posortować już gotową kolekcję za pomocą sortBy.


--------------------
Go to the top of the page
+Quote Post
GrupaZero
post 1.06.2018, 08:55:24
Post #11





Grupa: Zarejestrowani
Postów: 7
Pomógł: 0
Dołączył: 30.05.2018

Ostrzeżenie: (0%)
-----


Hej,

Jest to bardzo często spotykany problem, gdy chcesz posortować lub też filtrować wyniki na bazie relacji.
Najlepszym rozwiązaniem w takim przypadku jest dynamiczne zbudowanie odpowiedniego zapytania ze wszystkimi JOIN'ami jakie są potrzebne. Każda tabele powinna posiadać jakiś alias, a następnie na bazie pól, które dostaniesz do sortowania/filtrowania wprowadzasz odpowiednie warunki. Cała magia polega na tym, że na końcu nie wyciągasz wszystkich pól, a jedynie tą główną tabelę Eloquent i dopiero potem doczytujesz pozostałe relacje (->with() lub ->load()).

Tutaj masz przykładową implementację z tym, że jest to już trochę bardziej zaawansowane, ponieważ używam własnego QueryBuilder'a do rozkminienia jakie relację muszę załadować, ale mniej więcej widać koncepcję
https://github.com/GrupaZero/cms/blob/maste...y.php#L296-L330

Tutaj może to być nawet lepiej widoczne, wystarczy do tego zapytania dodać odpowiedni orderBy
https://github.com/GrupaZero/cms/blob/maste...y.php#L105-L116
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 19.04.2024 - 10:44