skip to Main Content

First, let me apoligise for the picture. I know its not suppose to be posted like this.

Bellow I have two collections. I want to update the key->value pair in collection1 with the values in collection2. Collection1 contains way more items including the ones in collection2

The keys in collection2 exist 100% in collection1.

I have tried a few suggestions without success like

$updatedCollection = $collection1->map(function ($item) use ($collection2) {
    $matchingItem = $collection2->where('id', $item['id'])->first();
    
    if ($matchingItem) {
        return array_merge($item, $matchingItem);
    }
    
    return $item;
});

and

    $res = $collection1->map(function ($item) use ($collection2) {
        $item = (array)$item;

        $matchingItem = $collection2->where('id', $item['id'])->first();

        if ($matchingItem) {
            return array_merge($item, $matchingItem);
        }

        $itemZ[] = (object)$item;
        $itemZZ = (object)$itemZ;
        $itemZZZ = collect($itemZ);

        return $itemZZZ;
    });

But mostly I get a collection with the items being an array where it should be an class and also the values arn’t updated.
I did not think it would be this tricky, but I cant seem to get it to return the same format as the original. and the update fails aswell.

enter image description here

4

Answers


  1. you can use array merge and data_get

    here’s a basic example

    $array1 = collect([
        ['key1' => 0, 'key2' => 1],
        [],
        [],
        ['key1' => 6, 'key2' => 7],
    ]);
    
    $array2 = collect([
        ['key1' => 11, 'key2' => 10],
        ['key1' => 2, 'key2' => 3],
        ['key1' => 4, 'key2' => 5],
        ['key1' => 12, 'key2' => 13],
        ['key1' => 14, 'key2' => 15],
    ]);
    

    merging based on array1 collection items (array2 item values will overwrite array1 items);

    return $array1->map( fn($item, $key) => array_merge($item, data_get($array2, $key) ?? [] ) );
    
    //output
    [
        { key1: 11, key2: 10 },
        { key1: 2, key2: 3 },
        { key1: 4, key2: 5 },
        { key1: 12, key2: 13 }
    ]
    

    merging based on array2 collection items (array1 item values will overwrite array2 items);

    return $array2->map( fn($item, $key) => array_merge($item, data_get($array1, $key) ?? [] ) );
    //output
    [
        { key1: 0, key2: 1 },
        { key1: 2, key2: 3 },
        { key1: 4, key2: 5 },
        { key1: 6, key2: 7 },
        { key1: 14, key2: 15 }
    ]
    

    Also, post the actual result of the collection you are trying to merge,

    you can get them by

    return [
        'c1' => $collection1,
        'c2' => $collection2
    ];
    

    or

    dd( $collection1->toArray(), $collection2->toArray() );
    
    Login or Signup to reply.
  2. I will try to answer this with example

    $collection1 = collect([
        ['id' => 1, 'name' => 'John'],
        ['id' => 2, 'name' => 'Jane'],
        ['id' => 3, 'name' => 'Bob'],
    ]);
    
    $collection2 = collect([
        ['id' => 1, 'name' => 'John Doe'],
        ['id' => 3, 'name' => 'Bob Smith'],
    ]);
    
    $updatedCollection1 = $collection1->map(function ($item) use ($collection2) {
        $matchingItem = $collection2->where('id', $item['id'])->first();
        if ($matchingItem) {
            return array_merge($item, $matchingItem);
        }
        return $item;
    });
    
    // $updatedCollection1 now contains the following values:
    // [
    //     ['id' => 1, 'name' => 'John Doe'],
    //     ['id' => 2, 'name' => 'Jane'],
    //     ['id' => 3, 'name' => 'Bob Smith'],
    // ]
    

    This approach works with unique key (here id is unique)

    Login or Signup to reply.
  3. Since you have 2 Collection, one could simply use merge of Collection to merge this 2 Collections together:
    https://laravel.com/docs/master/collections#method-merge

    From the description

    "[…]If a string key in the given items matches a string key in the original collection, the given item’s value will overwrite the value in the original collection[…]"

    So, as far as I understand it, this is exactly what you want to get.

    Login or Signup to reply.
  4. Because $matchingItem and $item are a class instance. To use array_merge, you need to convert them to array and to get object response, convert the result of array_merge to object

    $updatedCollection = $collection1->map(function ($item) use ($collection2) {
        $matchingItem = $collection2->where('id', $item['id'])->first();
        
        if ($matchingItem) {
            return (object) array_merge((array) $item, (array) $matchingItem);
        }
        
        return $item;
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search