I'm confused as to how database relationship works.
Say I have a Border Crossing('crossing'), which has two Directions('north', 'south'), each of which direction has 2 types of lanes ('normal','fast'), each of which lane has 2 metrics (=data) ('delay','queue_length').
In reality there are several crossings, with more lane types and more metrics.
How the heck should I store that in a database? I've used databases before, but never did table joins or one-to-many or anything like that.
I came across Datamapper and since I'm learning how to us Sinatra I thought I'd give it a go. In the tutorial (http://datamapper.org/getting-started.html), the "one-to-many" part just screamed "this is what you need", so I started fiddling around.
require 'data_mapper'
DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/development.db")
class Crossing
include DataMapper::Resource
property :id, Serial
property :name, String,:unique=>true
has n, :directions
end
class Direction
include DataMapper::Resource
property :id, Serial
property :direction, String,:unique=>true
belongs_to :crossing
has n, :lanes
end
class Lane
include DataMapper::Resource
property :id, Serial
property :lane, String
belongs_to :direction
has n, :datas
end
class Data
include DataMapper::Resource
property :id, Serial
property :name, String,:unique=>true
property :value, String
belongs_to :lane
end
DataMapper.finalize.auto_migrate!
I just thought this looked so elegantly put: "crossing has n directions, directions has n lanes, etc"
Then:
Crossing.create(:name => "crossing")
Direction.create(:direction => "north")
Direction.create(:direction => "south")
Lane.create(:lane => 'normal')
Lane.create(:lane => 'fast')
Data.create(:data => 'delay')
Data.create(:data => 'queue_length')
// now how do I retrieve find the data of a lane of a direction of a crossing?
Now, what I will input and retrieve all the time is the Data part. Does this whole thing make sense or I'm just not understanding what table associations are for? I know I could just have a gigantic object instead of this but I'm pretty sure that's a weird way of doing things.
@crossing = {
'crossing name' => {
:directions => {
:north => {
:normal => {
:delay => '10 min',
:queue => '100 m'
},
:fast => {
:delay => '1 min',
:queue => '10 m'
}
},
etc etc etc
}
and then access the data like @crossing[:north][:normal][:delay]....but I kinda feel like a database would be better?
Am I making any sense in any way? Anybody got some pointers for a young grasshoper?
I would rather go with this structure:
Data
belongs to Crossing
, Direction
and Lane
; it has properties for delay
and queue
Direction
has many Data
, and has exactly two rowsLane
has many Data
, and has exactly two rowsCrossing
has many Data
, and has many rowsThe reason is, you don't want to repeat the strings "north"
, "south"
etc in your database.
Then, first seed the database with constant tables:
Direction.create(direction: 'north')
Direction.create(direction: 'south')
Lane.create(lane: 'normal')
Lane.create(lane: 'fast')
Then you can make your crossings:
cool_crossing = Crossing.create(name: 'My Cool Crossing')
not_cool_crossing = Lane.create(name: 'My Not So Cool Crossing')
and add data points:
north = Direction.first(name: "north")
normal = Lane.first(name: "normal")
Data.create(
crossing: cool_crossing,
lane: normal,
direction: north,
delay: 10,
queue: 1
)
and retrieve data by:
all_data_for_cool_crossing = Data.all(
crossing: cool_crossing
)
or
data_for_cool_crossing_normal_north = Data.first(
crossing: cool_crossing,
lane: normal,
direction: north
)