-1

I have a collection object which includes the array of Model objects and I would like to select specific fields from the model.

Illuminate\Database\Eloquent\Collection Object
(
    [items:protected] => Array
        (
            [0] => App\Model Object
            [1] => App\Model Object
            [2] => App\Model Object
        )
)

Now I would like to select some fields from the model object. When I try to do the following syntax

print_r($collection->select('filed a', 'field b'));

then the following error occurs.

BadMethodCallException in Macroable.php line 74: Method select does not exist.

I think select can work directly with the eloquent model but not with a collection.

3 Answers 3

1

Are you looking for only()

$filtered = $collection->only(['list', 'of', 'fields', 'to', 'keep']);

or perhaps mapWithKeys()

Sign up to request clarification or add additional context in comments.

4 Comments

I was thinking of only or pluck, however the searched values are not array keys, but object properties.
@Thomas I suppose pluck() works on object too. I tested with a collection of Model Objects and it worked.
@Thomas now I understand your point, the keys of each object are not preserved. A better way would be to map over it.
@AlexMalikov Indeed only() works with the first level keys of the collection.
0

You are correct that select is not present on the Collection class.

What you can do is map, filter or transform the collection yourself e.g.

$whiteList = ['filed a', 'field b'];

$filledOnly = $collection->map(function ($item) use ($whiteList) {
    $properties = get_object_vars($item);

    foreach ($properties as $property) {
        if(!in_array($property, $whiteList) {
              unset($item->{property});
        }
    }

    return $item;
});

The problem is in PHP once a property (or field) is set on an object, you really have to unset it or create new objects of the same class). This is why I came up with this solution.

Question is: How did you retrieve this collection in the first place, could you not add the select to the query itself?

2 Comments

I also want the same structure that I have. So your answer will return me the array, not the eloquent model.
@sachinkumar You should specify in your question what you want. There you say nothing about that you need to same model, just that you want to select the fields from the model.
0

The best would have been to select the fields you need before you execute the query on the model. However, you can use map() if you want to preserve the initial collection or transform() if you want to override the collection (for example):

$selected_fields = ['filed a', 'field b']
$models->map(function ($zn) use ($selected_fields) { 
        return $zn->newInstance(array_only($zn->getAttributes(), $selected_fields));
    })->toArray();

newInstance() method creates a new empty instance of that model then getAttributes() retrieves the attributes present in the model. So the initial model is preserved in this process.

For reference sake, the implementation of newInstance() can be found on at Illuminate\Database\Eloquent\Model class and it is as follows (on Laravel 5.2):

    /**
     * Create a new instance of the given model.
     *
     * @param  array  $attributes
     * @param  bool  $exists
     * @return static
     */
    public function newInstance($attributes = [], $exists = false)
    {
        // This method just provides a convenient way for us to generate fresh model
        // instances of this current model. It is particularly useful during the
        // hydration of new objects via the Eloquent query builder instances.
        $model = new static((array) $attributes);

        $model->exists = $exists;

        return $model;
    }

1 Comment

For anyone coming along later to try this, the answer works great, but array_only was replaced in Laravel 5.7 with Arr::only. And note that the attributes you want to select must be "fillable" attributes in the model for this to work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.