1

I'm not sure how to best structure my tables so that the storage and querying is efficient and easy..

This is what i have:

  • rooms table - containing 10+ different room types (Kitchen, Lounge, etc), (with a unique ID)
  • properties_rooms lookup table - the Properties ID and the Room_id
  • properties table - containing many different properties (with a unique ID)

In addition to the above, i need to be able to capture a specific note and level attribute for each Property/Room combination, for example:

  • (Property ID - '1') -> from properties table
  • (Property Name -'Sunny House')-> from properties table
  • (Room ID - '2')-> from properties_rooms lookup
  • (Room Name - 'Bedroom')-> from Rooms table
  • (Level - "Ground Floor")-> what table??
  • (Note - "Twin beds")-> what table??

Level and Note above are specific to the combination of the property and the room type, so seem to make sense to be in the lookup?

I have the following scheme setup:

Properties

Schema::create('properties', function (Blueprint $table) {
   $table->id();
   .....

Rooms and Properties_Rooms

Schema::create('rooms', function (Blueprint $table) {
     $table->id();
     $table->string('name')->unique();
     $table->timestamps();
});

Schema::create('properties_room', function (Blueprint $table) {
     $table->id();
     $table->foreignId('properties_id')->constrained('properties')->onDelete('cascade');
     $table->foreignId('room_id')->constrained('rooms')->onDelete('cascade');
     $table->string('level');
     $table->string('note');
     $table->timestamps();
     $table->unique(['properties_id','room_id']);
});

Models

Rooms
public function properties()
{
     return $this->belongsToMany(Properties::class);
}

Properties
public function rooms()
{
     return $this->belongsToMany(Room::class);
}

The "Level" and "Note" fields seem correct to be in the lookup file. But i'm not sure if this is correct, or how to access them?

In my blade view, these all work:

  • {{ $properties }} - Property Table Attributes
  • {{ $properties->rooms }} - Room Table Attributes

But through the "Room" attributes, i'm not able to see the information held in the lookup file, which was obviously used?

Ben Holmes
  • 73
  • 7
  • A `Room` can belong to many `Properties`? – Peppermintology Feb 12 '21 at 19:13
  • 1
    [`withPivot()`](https://stackoverflow.com/questions/49370881/laravel-belongstomany-pivot-with-multiple-columns) can help you to get extra details from junction table – M Khalid Junaid Feb 12 '21 at 19:14
  • 1
    Thank's Khalid. I think withPivot() is what i need. Unflux, yes the Room is just a type. So that type could belong to many properties. The specific of that room, the level and attributes, then being captured in the junction/lookup/pivot table.. – Ben Holmes Feb 12 '21 at 19:47

1 Answers1

0

Your privot table doesn't seem to be adding anything of value, so I would be inclide just to put your Room specific data on the Room table and create a relationship with a Property.

Property class

public function rooms()
{
  return $this->hasMany(Room::class);
}

Room class

public function property()
{
  return $this->belongsTo(Property::class);
}

Rooms table

Schema::create('rooms', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('floor');
    // etc ...
    $table->foreignId('property_id')->constrained();
    $table->timestamps();
});

Update

I might be misunderstanding your scenario, however, given the information provided I still think a pivot table is adding an unnecessary component/complexity. A Room does not belong to many Property, it exists in one Property. The pivot also adds an additional join which can be avoided by combining your tables.

Take the information about a Room from your pivot table and add it to your rooms table along with a foriegn key to the related Property (see above). You can add anything you want that describes a Room (e.g. floor area, if it has an en-suite, etc.). Granted you might get a few columns in your rooms table that only make sense for a particular Room type, however, a few empty fields is not going to make the world implode (that's only achievable when dividing by zero). Keep it simple, don't over complicate things.

A very basic example of how you might get a list of your properties and related rooms might look something like the following.

return view('properties', [
    'properties' => Property::with('rooms')->paginate(10)
]);

Then in your view you could loop over the properties and their rooms.

@foreach ($properties as $property)
    <h4>{{ $property->name }} has {{ $property->rooms->count() }} @choice('room|rooms', $property->rooms->count())</h4>

    @foreach ($property->rooms as $room)
        <p>{{ $room->type }} is located on the {{ $room->level }} floor</p>
    @endforeach
@endforeach
Peppermintology
  • 9,343
  • 3
  • 27
  • 51
  • This may results as data redundancy in rooms table like there will be 2 entries in table if a room has kitchen and room without kitchen, and so on with the floor values – M Khalid Junaid Feb 12 '21 at 19:30
  • 1
    The main problem with just two tables (properties and rooms) is that the room's table should be an exhaustive list of all possible room combinations. So there would be alot of redundancy for small properties. Plus not sure how multiple properties would like to the same record in the rooms table?! Looking into the withPivot() option, that seems to be what i need. Thanks – Ben Holmes Feb 12 '21 at 19:41
  • @BenHolmes At present your `rooms` table is not representing a `Room` though, it is representing a `RoomType` (kitchem, bathroom, bedroom). Your pivot table is more representitive of a `Room` and that data could be on the `rooms` table with a relationship to `Property`. Yes two `properties` can have a `kitchen`, but it is not the same `kitchen`. – Peppermintology Feb 12 '21 at 20:02
  • @unflux. I understand that the data in the pivot table is more representative of a room instance. That's what i hoped it would be. I think withPivot() allows me now the option to access the information in the pivot table. But maybe its cleaner to use the relationship you mentioned. Out of interest, what would that look like? – Ben Holmes Feb 12 '21 at 20:46
  • @BenHolmes I have updated my comment. Not really much more code I can add to what was already there but a bit more explination as to my reasoning. – Peppermintology Feb 12 '21 at 21:34