Reputation: 1421
I have a table of stock movements, which shows a history of a product (receiving, moving location etc.)
I have two queries which calculate (via aggregate sums):
Both of these queries return a collection of the same models. They will always have the same number of results in each, and the product_id's will always be the same. The only part that is different is the received/live qty and I want to somehow merge the individual records into a new collection. i.e.
Single record from query 1:
0 => StockMovement {#1602 ▼
#original: array:2 [▼
"live_qty" => "8"
"product_id" => "2606598e-4150-461a-9e91-10d67cce8daa"
]
}
Single record from query 2;
0 => StockMovement {#1602 ▼
#original: array:2 [▼
"received_qty" => "15"
"product_id" => "2606598e-4150-461a-9e91-10d67cce8daa"
]
}
I am trying to end up with a merged result which looks like the following:
0 => StockMovement {#1602 ▼
#original: array:3 [▼
"received_qty" => "15"
"live_qty" => "8"
"product_id" => "2606598e-4150-461a-9e91-10d67cce8daa"
]
}
I want to do this in a way that does not convert the Product object to an array, as I need the relationships that are embedded within it.
Currently, I have hacked this as follows:
$live = $this->liveQtyCollection();
$merged = $this->receivedQtyCollection()->map(function(StockMovement $received) use($live){
$line = $live->where('product_id', $received->product_id)->first();
return arrayToObject(array_merge($received->toArray(), $line->toArray()));
});
return $merged;
The arrayToObject
function, recursively converts the array back into an object so I can use the arrow selector in the same way as when it was its original collection, but I am sure there must be a better way!
I have tried:
My end goal is to be able to use the resulting collection as follows:
@foreach($stockMovements as $stockMovement)
{{ $stockMovement->id }}
{{ $stockMovement->live_qty }}
{{ $stockMovement->received_qty }}
@endforeach
Upvotes: 6
Views: 12819
Reputation: 6309
I know you mentioned in your question that you did not mean collections and also that you had already tried merging, but for the sake of discussion I thought I'd throw my answer in the mix, as this worked precisely for what I needed; merging the responses of two model calls.
$quote = \App\AllQuotes::withoutGlobalScopes()->find($quote_id);
$settings = \App\Settings::findOrFail(1);
$settings = collect($settings);
$quote = collect($quote);
$merged = $quote->merge($settings);
return $merged;
You have to first encapsulate the model responses as collections with the collect
helper, then you can merge them together. The output then treats it as a logical join, maintaining the data from both models in a singular output.
Upvotes: 1
Reputation: 1903
You could do something like this:
$live = $this->liveQtyCollection()->keyBy('product_id')
$merged = $this->receivedQtyCollection()->map(function(StockMovement $received) use($live){
$received->live_qty = $live->get($received->product_id)->live_qty ?? null;
return $received;
});
Upvotes: 0
Reputation: 1537
You can use this code:
$collection = collect();
$cars = Car::all();
$bikes = Bike::all();
foreach ($cars as $car)
$collection->push($car);
foreach ($bikes as $bike)
$collection->push($bike);
Upvotes: 8