Search code examples
laravelcollectionslaravel-5.3

Eloquent collections methods such as only or except return an empty collection


From the docs, I have tested the following example with the ->only() method

$collection = collect(['product_id' => 1, 'name' => 'Desk', 'price' => 100, 'discount' => false]);

$filtered = $collection->only(['product_id', 'name']);

$filtered->all();

// ['product_id' => 1, 'name' => 'Desk']

and it is working indeed.

However, when I apply that method to a collection I get from the database (Model),

$myCollection = MyModel::orderBy('id','desc')->paginate(5);
$filtered=$myCollection->only(['id']);
        dd(filtered);

the collection returned is empty!

Collection {#199 ▼
  #items: []
}

If I dd($myCollection); the collection gotten from the database, it is indeed full of the appends, attributes, and so on stuff. The data appears correctly in the table blade view.

But if I apply either the ->only() or ->except() to $myCollection methods ... the returned collection is empty.

For example, this is the piece of the collection, where I only want to show the id attribute, for example, or some more but not all:

LengthAwarePaginator {#218 ▼
  #total: 3041
  #lastPage: 609
  #items: Collection {#219 ▼
    #items: array:5 [▼
      0 => MyModel {#220 ▼
        #dates: array:1 [▶]
        #appends: array:5 [▶]
        #connection: null
        #table: null
        #primaryKey: "id"
        #keyType: "int"
        #perPage: 15
        +incrementing: true
        +timestamps: true
        #attributes: array:12 [▼
          "id" => 3041
          "date" => "2017-01-25"
          "value1" => "12"
          "value2" => "20"
          "value3" => "22"
          "value4" => "25"
          "value5" => "46"
          "value6" => "48"
          "value7" => "50"
          "value8" => "$60,000,000.00"
          "created_at" => null
          "updated_at" => null
        ]

But when I apply ->only(['id']), the collection is returned empty.

I have tested it without the paginate and the problem of the empty collection is still the same, so I don't think it has to do with the LengthAwarePaginator.

Workaround Unfortunately I am achieving this the hard way:

    $filtered = collect(['id'=>$myCollection->pluck(['id']),'Value1'=>$myCollection->pluck('value1')]);
dd($filtered);

Now I am getting the desired collection where, for example I just want two attributes or columns from the database:

Collection {#212 ▼
  #items: array:2 [▼
    "id" => Collection {#201 ▶}
    "value1" => Collection {#211 ▶}
  ]
}

Why is this happening? What am I missing? How can I fix it?


Solution

  • Take note that only() will return item(s) with the specified key which is applied to an array with keys or associative array. As example given, it is array with keys

    ['product_id' => 1, 'name' => 'Desk', 'price' => 100, 'discount' => false]
    

    However, if you test to use only() with collection from eloquent results, which contains an array of collections / objects (without key).

    [ object, object, object ]
    

    It will work if the collection contain keys.

    [ 'product_id' => object, 'name' => object ]
    

    Thus, in your case to filter only the values of specified keys, I suggest to use pluck() or map()