0

I have a Response, that is of the following:

[{
      "id":7,
      "name": "Product Name",
      "versions":[
         {
            "id":1,
            "amount":199
         },
         {
            "id":2,
            "amount":99
         }
      ]
}]

In Laravel Controller I did the following,

$q = Product::select(*)->with('getProductVersion');
$product = $q->WhereHas('getProductVersion', function($q){
           $q->orderBy('amount', 'asc'); })->get();

return $product;

getProductVersion is a ManytoMany relation between Product and Version.

However the Ordering isnt correct, the Expected result is

[{
      "id":7,
      "name": "Product Name",
      "lowest_amount": 99,
      "versions":[
         {
            "id":2,
            "amount":99
         },
         {
            "id":1,
            "amount":199
         }
      ]
}]

Sort the Array of Object and Print the lowest value to Parent Array.

Boheman
  • 3
  • 2
  • You asked for `orderBy('amount', 'asc')` -- meaning the amount should be ascending, which is exactly what you got. If you want the smaller values last, use `orderBy('amount', 'desc')`. – Alex Howansky May 12 '23 at 15:21
  • Sorry my mistake, i have edited the question – Boheman May 12 '23 at 15:27
  • `whereHas()` filters the parent Model's query, but doesn't return anything; you're getting the versions in the default order, since `with()` is the one that returns associated records, but you're not passing any sorting logic to `with()`. Use `with(['getProductVersion' => function ($q) { // sorting logic here })])` or [`withWhereHas()`](https://laravel.com/docs/10.x/eloquent-relationships#constraining-eager-loads-with-relationship-existence) if you need to both filter and sort. – Tim Lewis May 12 '23 at 15:32

1 Answers1

1

You need to change WhereHas, and use with

$q = Product::select('*')->with(['getProductVersion' => function($query) {
    $query->orderBy('amount', 'asc');
}])->get();

the with() method to eagerly load the getProductVersion relationship with a closure that orders the related versions by the amount attribute in ascending order

refer to this please: https://stackoverflow.com/a/30232227/4613828

More if you need to assign the lowest value:

$products = Product::with(['getProductVersion' => function($query) {
    $query->orderBy('amount', 'asc');
}])->get()->map(function($product) {
    $product->lowest_amount = $product->getProductVersion->min('amount') ?? null;
});

return $product;
  • Thankyou so much that fixed the sorting part. Now how can i append the sorted "lowest_amount" as a new column in the result ? – Boheman May 12 '23 at 15:32
  • I think you should modify add some code handling this: ```php if (!empty($product->versions)) { $product->lowest_amount = $product->versions[0]->amount ?? null; } else { $product->lowest_amount = null; } ``` – Abdelrahman M. Allam May 12 '23 at 15:35
  • Also, `versions` is not set, but `getProductVersion` is, so, more concise: `$product->lowest_amount = $product->getProductVersion->min('amount') ?? null;` – Tim Lewis May 12 '23 at 15:42
  • I did update, and used `map` to the item for version's lowest price, without doing another query - data already loaded – Abdelrahman M. Allam May 12 '23 at 15:46
  • 1
    That's a little better, but still kinda crazy. First, `$product` is a bad variable name, since `->get()` returns multiple, so it should be `$products`. Next, defining variables for a single use, like `$lowest_version = ...`, then `$item->lowest_version = $lowest_version` is silly, as is `$versions->first() ? $versions->first()->amount : null`, then `$item->versions = $versions`; why are you assigning it again? You can literally do all of this in a single line: `$products = Product...->map(function ($product) { $product->lowest_amount = $product->getProductVersion->min('amount') ?? null; });` – Tim Lewis May 12 '23 at 15:50
  • I liked your attention to making the code clean and more readable variable name, for the `map` I will take your suggestion improvement to the answer, thank you – Abdelrahman M. Allam May 12 '23 at 16:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253631/discussion-between-abdelrahman-m-allam-and-tim-lewis). – Abdelrahman M. Allam May 12 '23 at 16:04
  • No problem Ultimately this question isn't about optimization or anything like that, but Laravel provides a lot of useful methods. Apologies, I don't have time for chat right now, but cheers; answer looks great now! – Tim Lewis May 12 '23 at 16:04