Framework: unique() method in the Collection class not returning unique items?

Created on 2 Jul 2018  Â·  7Comments  Â·  Source: laravel/framework

  • Laravel Version: 5.6.*
  • PHP Version: ^7.1.3
  • Database Driver & Version: MySQL (not sure about the version)

Description:

First of all let me apologize if this is incorrect, but have been already a few days trying to figure out this in forums and chats, and haven't been able and i want to confirm wether is an issue in the framework or not.

Using Resource collections, I have a collection with two items from my Ingredient model, as you can see the items are actually the same one.

Collection {#1126 â–¼
  #items: array:2 [â–¼
    0 => Ingredient {#1014 â–¼
      +translatedAttributes: array:1 [â–¶]
      #cascadeDeletes: array:1 [â–¶]
      #fillable: array:1 [â–¶]
      #connection: "mysql"
      #table: null
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #attributes: array:5 [â–¶]
      #original: array:7 [â–¼
        "id" => 16
        "code" => "odio"
        "created_at" => "2018-07-01 13:49:59"
        "updated_at" => "2018-07-01 13:49:59"
        "deleted_at" => null
        "pivot_dish_id" => 1
        "pivot_ingredient_id" => 16
      ]
      #changes: []
      #casts: []
      #dates: []
      #dateFormat: null
      #appends: []
      #dispatchesEvents: []
      #observables: []
      #relations: array:1 [â–¶]
      #touches: []
      +timestamps: true
      #hidden: []
      #visible: []
      #guarded: array:1 [â–¶]
      #defaultLocale: null
      #forceDeleting: false
    }
    1 => Ingredient {#1119 â–¼
      +translatedAttributes: array:1 [â–¶]
      #cascadeDeletes: array:1 [â–¶]
      #fillable: array:1 [â–¶]
      #connection: "mysql"
      #table: null
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #attributes: array:5 [â–¶]
      #original: array:7 [â–¼
        "id" => 16
        "code" => "odio"
        "created_at" => "2018-07-01 13:49:59"
        "updated_at" => "2018-07-01 13:49:59"
        "deleted_at" => null
        "pivot_dish_id" => 2
        "pivot_ingredient_id" => 16
      ]
      #changes: []
      #casts: []
      #dates: []
      #dateFormat: null
      #appends: []
      #dispatchesEvents: []
      #observables: []
      #relations: array:1 [â–¶]
      #touches: []
      +timestamps: true
      #hidden: []
      #visible: []
      #guarded: array:1 [â–¶]
      #defaultLocale: null
      #forceDeleting: false
    }
  ]
}

I supposed from when I looked into the Collection class that the unique() method would return the unique items, from the collection array, but when I call the method on that collection object $ingredients->unique(), I keep getting both elements in the collection.

Again at this point, I'm not sure if I'm assuming incorrectly, or this is something that is actually not working as expected, have pasted the entire JSON of the object, in case you see there is something that I'm missing.

Really sorry if this is not a real issue and I make you lose time, will try to explain how i get to this point in the steps to reproduce.

Steps To Reproduce:

I'm creating something similar to what is in https://github.com/developerdino/example-articles-api

Articles -> Dishes
Comments -> Ingredients

Some dishes will have the same ingredients, therefore I'm trying to not repeat them as part of the includes of the response object which is done I believe in the following file https://github.com/developerdino/example-articles-api/blob/master/app/Http/Resources/ArticlesResource.php when we are merging the collections $included = $authors->merge($comments)->unique();

That is where I'm expecting to filter out the duplicate items in the collection, from what I see in the ValueRetriever method in the Collections class, we are not retrieving the original property of the object, therefore I'm not 100% sure if this the intended behavior or not of the method, thanks!

Most helpful comment

Use this:

(new \Illuminate\Database\Eloquent\Collection($ingredients))->unique();

There are two Collection classes in Laravel:
Illuminate\Support\Collection and Illuminate\Database\Eloquent\Collection

The first one is the base class for the second one. When you fetch models from the database, you receive a collection of the second class. Certain methods (e.g. pluck()) convert this collection to the base class.

The second class uses the models' primary key to remove duplicates (the behavior you are expecting).
The first class, however, compares the actual values. This is where your models are not the same: They have the same id, but the PHP objects are different (#1014 vs #1119).

All 7 comments

What's the result of dd(get_class($ingredients));?

result of that is the following: "IlluminateSupportCollection"

Use this:

(new \Illuminate\Database\Eloquent\Collection($ingredients))->unique();

There are two Collection classes in Laravel:
Illuminate\Support\Collection and Illuminate\Database\Eloquent\Collection

The first one is the base class for the second one. When you fetch models from the database, you receive a collection of the second class. Certain methods (e.g. pluck()) convert this collection to the base class.

The second class uses the models' primary key to remove duplicates (the behavior you are expecting).
The first class, however, compares the actual values. This is where your models are not the same: They have the same id, but the PHP objects are different (#1014 vs #1119).

That worked perfectly, thanks for your help @staudenmeir

Sorry for having wasted your time, I thought for a minute this could be some sort of issue I was running into, thanks once again. Let me know if you want me to close this issue.

Thanks!

You're welcome. Yes, please close the issue.

You can also pass a key attribute to the unique call.

$fetched->unique('id');

To me it looks cleaner than passing that huge namespace class.

@hvlucas that works fine as well, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Anahkiasen picture Anahkiasen  Â·  3Comments

jackmu95 picture jackmu95  Â·  3Comments

YannPl picture YannPl  Â·  3Comments

lzp819739483 picture lzp819739483  Â·  3Comments

ghost picture ghost  Â·  3Comments