Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mcadio's avatar

How to filter and combine collections

I have 2 collections, one for appointment timeslots: I get the proper 18 records:

dd($timeslots)
  0 => {#1910 ▼
      +"appt_date": Carbon\Carbon @1662465600 {#1976 ▶}
      +"appt_time": Carbon\Carbon @1662465600 {#1976 ▼
        #endOfTime: false
        #startOfTime: false
        #constructedObjectId: null
        #localMonthsOverflow: null
        #localYearsOverflow: null
        #localStrictModeEnabled: null
        #localHumanDiffOptions: null
        #localToStringFormat: null
        #localSerializer: null
        #localMacros: null
        #localGenericMacros: null
        #localFormatFunction: null
        #localTranslator: null
        #dumpProperties: array:3 [▶]
        #dumpLocale: null
        #dumpDateProperties: null
        date: 2022-09-06 08:00:00.0 America/New_York (-04:00)
      }
      +"appt_type_id": 2
    }
    ... all the other records
    17 => {#1741 ▶}
 ]
  #escapeWhenCastingToString: false
}

I also have a collection of booked appointments, and there are 10 in it:

dd($booked)
lluminate\Support\Collection {#2190 ▼
  #items: array:10 [▼
    0 => App\Models\Appt {#2047 ▶}
     ... all the other records
    9 => App\Models\Appt {#2151 ▼
      #connection: "mysql"
      #table: "appt"
      +primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      +preventsLazyLoading: false
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #escapeWhenCastingToString: false
      #attributes: array:7 [▼
        "id" => 19415
        "appt_type_id" => 2
        "appt_status_id" => 2
        "appt_date" => "2022-09-06"
        "appt_time" => Carbon\Carbon
		"patient_id" => 44
		"appt_note" => "some note"
 ]
  #escapeWhenCastingToString: false
}

I need to merge the data, but only keep the timeslots that are NOT in the appts collection and I need it in order by the carbon date. I've tried naming the timeslot field appt_time and so many things but I just cannot get it!

I've tried $timeslots->merge($booked). I've tried $timeslots->concat($booked), I've tried filering the $times collection using $filtered = $times->pluck('timeslot')->whereNotIn('timeslot', $booked->pluck('appt_time'));

It should look something like this:

0 => { 
	appt_date: '2022-09-06, 
	appt_time: "08:00:00" (Carbon or String, whatever works), 
	appt_type_id: 2 
}
1 -> {  "id" => 19415
        "appt_type_id" => 2
        "appt_status_id" => 2
        "appt_date" => "2022-09-06"
        "appt_time" => Carbon\Carbon (that shows 08:10:00 for that date)
		"patient_id" => 44
		"appt_note" => "some note"
}
2 => { 
	appt_date: '2022-09-06, 
	appt_time: "08:20:00" (Carbon or String, whatever works), 
	appt_type_id: 2 
}

.. all the rest of the records.

Can somene please help me? In my view, I display basic info about the booked appt OR a button to schedule that time, and it's the final piece I just can't get right.

0 likes
1 reply
rodrigo.pedra's avatar
Level 56

Hey @mcadio first of all, on your next interactions wrap your code blocks with either 3 backticks or 3 tildes, like this:

~~~
// code goes here
~~~

or

```
// code goes here
```

This way it is easier for us to help you out.

Regarding your question, if I got it right, you could try this:

$merged = $timeslots->map(function ($timeslot) use ($booked) {
    $record = $booked
        ->filter(function (Appt $appointment) use ($timeslot) {
            return $appointment->appt_date === $timeslot->appt_date->toDateString()
                && $appointment->appt_time->toTimeString('minute') === $timeslot->appt_time->toTimeString('minute');
        })
        ->first();

    if ($record) {
        return $record->toArray();
    }

    return $timeslot;
});

$merged->dd();

Note I assumed the model's appt_date attribute is a string, based on the output you provided. If it is a carbon instance you will need to call $appointment->appt_date->toDateString() on the first comparison.

1 like

Please or to participate in this conversation.