0

Ich habe eine Rails-Anwendung, die Stationen (Wetterstationen) und Beobachtungen hat. Die App zeigt viele Wetterstationen auf einer Karte mit der aktuellen Windgeschwindigkeit und Richtung.Schienen begier_load mit Bedingungen für die Zuordnung

Ich habe eine Methode, die auf der stations#index Methode verwendet wird, die die Stationen auswählt und die neueste Beobachtung pro Station verbindet.

class Station < ActiveRecord::Base 
    has_many :observations 
    def self.with_observations(limit = 1) 
    eager_load(:observations).where(
     observations: { id: Observation.pluck_from_each_station(limit) } 
    ) 
    end 
end 

Observation.pluck_from_each_station gibt ein Array von IDs zurück. Die observations Tabelle enthält viele Tausende von Zeilen, so dass dies erforderlich ist, um zu verhindern, dass Schienen tausende von Datensätzen geladen werden. Diese Methode sollte alle Stationen Rückkehr

- ob das irgendwelche Beobachtungen oder nicht. Dies ist jedoch derzeit nicht der Fall.

it "includes stations that have no observations" do 
    new_station = create(:station) 
    stations = Station.with_observations(2) 
    expect(stations).to include new_station # fails 
end 

Von meinem Verständnis ein LEFT OUTER JOIN sollten alle Zeilen zurückgeben, ob die es Ergebnisse in der verknüpften Tabelle sind oder nicht. Warum funktioniert das nicht wie erwartet?

Dies ist ein Beispiel für die SQL generiert:

SELECT "stations"."id" AS t0_r0, 
     "stations"."name" AS t0_r1, 
     "stations"."hw_id" AS t0_r2, 
     "stations"."latitude" AS t0_r3, 
     "stations"."longitude" AS t0_r4, 
     "stations"."balance" AS t0_r5, 
     "stations"."timezone" AS t0_r6, 
     "stations"."user_id" AS t0_r7, 
     "stations"."created_at" AS t0_r8, 
     "stations"."updated_at" AS t0_r9, 
     "stations"."slug" AS t0_r10, 
     "stations"."speed_calibration" AS t0_r11, 
     "stations"."firmware_version" AS t0_r12, 
     "stations"."gsm_software" AS t0_r13, 
     "stations"."description" AS t0_r14, 
     "stations"."sampling_rate" AS t0_r15, 
     "stations"."status" AS t0_r16, 
     "observations"."id" AS t1_r0, 
     "observations"."station_id" AS t1_r1, 
     "observations"."speed" AS t1_r2, 
     "observations"."direction" AS t1_r3, 
     "observations"."max_wind_speed" AS t1_r4, 
     "observations"."min_wind_speed" AS t1_r5, 
     "observations"."temperature" AS t1_r6, 
     "observations"."created_at" AS t1_r7, 
     "observations"."updated_at" AS t1_r8, 
     "observations"."speed_calibration" AS t1_r9 
FROM "stations" 
     LEFT OUTER JOIN 
     "observations" 
     ON "observations"."station_id" = "stations"."id" 
WHERE "observations"."id" IN (450, 500, 550, 600, 650, 700, 750, 800); 
+1

'" Beobachtungen "." ID "IN (..)' Sollte innerhalb der ON-Klausel und nicht der WHERE-Klausel sein. – sagi

Antwort

1

Ich denke, das passiert, weil u Datensätze werden mit Ausnahme von wo "observations"."id" ist null nach dem left join:

eager_load(:observations).where(
    '"observations"."id" is null or "observations"."id" in (?)', Observation.pluck_from_each_station(limit) 
) 

Es ist logisch das Gleiche wie left join unter zwei Bedingungen, aber da Schienen diese Funktion nicht haben, können Sie mit der Klausel where umgehen.

+0

Es passiert, weil Bedingungen in der rechten Tabelle eines linken Joins in der ON-Klausel platziert werden sollten. Wenn sie sich in der WHERE-Klausel befinden, werden die Joins in einen inneren Join umgewandelt. – sagi

+0

@sagi: Ja, aber es kann auch in der 'Where' Klausel gemacht werden. – potashin

+0

Ja, aber das ist schlechte Praxis .. – sagi

Verwandte Themen