RedElement
RedElement

Reputation: 93

Merging duplicates and summing field in a multidimensional collection in Laravel 5.4

I've inherited a Laravel 5.4 project. Upgrading isn't an option and neither is a large scale rewrite so I'm stuck with what I've got. I have an eloquent collection that looks as follows when fetched from the database and simplified:

$orders

[
  {
    "item": Item 1,
    "status": 3,
    "qty": 2,
    "hotlist": null
  },
  {
    "item": Item 1,
    "status": 4,
    "qty": 5,
    "hotlist": null
  },
  {
    "item": Item 1,
    "status": 3,
    "qty": 1,
    "hotlist": true
  },
  {
    "item": Item 1,
    "status": 3,
    "qty": 1,
    "hotlist": null
  },
]

There are obviously more than 1 item but this will show what I'm more or less working with and what I need to accomplish. I'm attempting to give a report of items. If they are the same item, in the same status, and not on the hotlist they should be 1 line item with the total quantity. Using the above example I need an output like this example:

[
  {
    "item": Item 1,
    "status": 3,
    "qty": 3,
    "hotlist": null
  },
  {
    "item": Item 1,
    "status": 4,
    "qty": 5,
    "hotlist": null
  },
  {
    "item": Item 1,
    "status": 3,
    "qty": 1,
    "hotlist": true
  },
]

The only change is is the quantity of the first and last item have been summed and the duplicate item removed. I've come close using the following code:

$orders->groupBy('item')->flatMap(function ($items) {
  $quantity = $items->sum('qty');
  return $items->map(function ($item) use ($quantity) {
     $item->qty = $quantity;
     return $item;
  });
});

Obviously however it only takes into account the item name is the same then sums it, but I also need to verify the list and status. I've been banging my head against the wall with this one so I feel like it's got to be something simple I'm overlooking. Hopefully somebody can see what I'm missing.

Upvotes: 1

Views: 657

Answers (1)

Pei Qi Tea
Pei Qi Tea

Reputation: 304

Not very performant, but tentatively:

// make it a collection so we can use the helper methods
$collection = collect([]); 

$orders->each(function ($item) use ($collection) {
   $target = $collection->where('item', $item->item)
                        ->where('hotlist', $item->hotlist)
                        ->where('status', $item->status);
   if ($target->count() == 0) 
      $collection->push($item); // If it hasn't been added, add it to the collection
   else
      $target->first()->qty += $item->qty;
});

dd($collection); // double check

Upvotes: 2

Related Questions