niborocin's avatar

"with()" returns ID of associated model twice

I have the following piece of code to retrieve an instance of "Panel" with a single "Flag" associated to it. It is mentioned as "flag_id" in the database.

Panel::with('flag')->find($panelId, ['id', 'name', 'brightness', 'flag_id', 'geo_lat', 'geo_lng'])

This returns:

    "id": 2,
    "name": "Panel X",
    "brightness": 100,
    "flag_id": 5, //mentioned twice
    "geo_lat": "50",
    "geo_lng": "50",
    "flag": {
        "id": 5, //mentioned twice
        "name": "Off",
        "filename": "black",
        "is_special": 0
    }
}

Why is "flag_id" returned? If I leave it out in the columns parameter I get "flag" returned as null. Whats the trick here? Thanks!

0 likes
7 replies
niborocin's avatar

@MichalOravec I see, I tried it but I still get returned the "flag_id". I only want the id of the flag to get returned in the associated flag object and not in the panel object.

Panel::with('flag:id,name,filename,is_special')->find($panelId, ['id', 'name', 'brightness', 'flag_id', 'geo_lat', 'geo_lng'])

However, I don't quite get how I should use the foreign key you mentioned, as my "Flag" doesn't have a "panel_id" column. I think it is not needed then? If that's even the issue.

kokoshneta's avatar
Level 27

@niborocin Unless you provide a list of specific columns to retrieve, Eloquent will retrieve all columns from the database. Since there is a column called flag_id in your panels table, that row will always be included. In your case, you are even specifically telling Eloquent to retrieve that column by including it in the list you pass as the second parameter in the ->find() method call.

You could leave out flag_id from that list, but then of course the relationship won’t load, because the property needs to be set in order for Eloquent to know which IDs to look for when fetching the relevant rows from the subsequent database call.

In other words, the flag_id attribute is needed; you can’t avoid retrieving it. If you don’t want it in your Panel model, you need to manually remove it:

Panel::with('flag')
	->find($panelId, ['id', 'name', 'brightness', 'flag_id', 'geo_lat', 'geo_lng'])
	->each(fn ($item) => unset($item->flag_id))
;

But why is it so important that the flag_id column be removed from your Panel object? What harm does its presence do?

1 like
niborocin's avatar

@kokoshneta This is exactly what I was wondering about! If there is any way to tell eloquent to get the associated flag without mentioning it in the columns to retrieve, as that automatically includes the flag_id in the panel object. So there isn't, that's good to know, thank you and thanks for your suggestion to remove it afterwards!

As to why: It may seem petty but I am writing a REST-API and I want to keep the responses of the request non-redundant and have clean code in general. So modifying the collection afterwards is okay, but in my head I just thought that there has to be another way :)

kokoshneta's avatar

@niborocin If it’s for an API, you can also make an Eloquent resource for the model and make sure not to include that column in your toArray(). That would be the more ‘proper’ Laravel way to do it.

1 like

Please or to participate in this conversation.