How to filter by foreign id and local attribute via belongs_to?

115 views Asked by At

The following models are linked via belongs_to:

require 'mongoid'
class Sensor 
    include Mongoid::Document
    field :sensor_id, type: String
    validates_uniqueness_of :sensor_id
end

...

require 'mongoid'
require_relative 'sensor.rb'
class SensorData 
    include Mongoid::Document
    belongs_to :sensor
    field :date, type: Date
    field :ozonMax1h, type: Float
    field :ozonMax8hMittel, type: Float
    index({ date: 1, sensor_id: 1 }, { unique: true })
end

Here is a Sinatra app which provides a few API paths based on these models:

require 'sinatra'
require 'csv'
require_relative './models/sensor.rb'
require_relative './models/sensor_data.rb'

configure do
  Mongoid.load!('./mongoid.yml')
end

def prepare_for_export(sensor_data)
    converted_data = sensor_data.asc(:date).map do |e|
        {
            sensor_id: e.sensor.nil? ? :null : e.sensor.sensor_id,
            date: e.date,
            ozonMax1h: e.ozonMax1h,
            ozonMax8hMittel: e.ozonMax8hMittel
        }
    end
    converted_data
end

def convert_to_json(sensor_data)
    prepare_for_export(sensor_data).to_json
end

def convert_to_csv(sensor_data)
    data = prepare_for_export sensor_data
    csv_string = CSV.generate do |csv|
        csv << data.first.keys
        data.each do |hash|
            csv << hash.values
        end
    end
    csv_string
end

def get_recent
  max_date = SensorData.max(:date)
  SensorData.where(date: max_date)
end

def get_for_year(year)
  SensorData.where(:date.gte => Date.new(year, 1, 1)).where(:date.lte => Date.new(year, 12, 31))
end

def get_for_sensor(sensor)
  foo = SensorData.where(sensor_id: sensor)
  puts "hallo"
  return foo
end

get '/api/v1/stations' do
  content_type :json
  Sensor.all.map { |e| {sensor_id: e.sensor_id} }.to_json
end

get '/api/v1/sensordata/:year' do
  content_type :json
  convert_to_json get_for_year(params[:year].to_i)
end

get '/api/v1/sensordata/:year/csv' do
  convert_to_csv get_for_year(params[:year].to_i)
end

get '/api/v1/recent' do
  content_type :json
  convert_to_json get_recent
end

I would like to output the SensorData for a particular sensor such as here:

/api/v1/stations/:sensor_id/sensordata/:year/csv
1

There are 1 answers

2
Bassel Samman On BEST ANSWER

I am not sure what you are trying to do or even if you are still looking for an answer but here it goes. Something seems wrong with the models in the example you have here. Sounds like part of what you are doing would work if Sensor knows about sensor_data. So might need to add this to Sensor class:

has_many :sensor_data

Though the singular of data is datum. The class would be expected to be SensorDatum. If you can't change it, you need to tell Mongoid the class_name to expect in the has_many is actuall SensorData.

You CAN specify foreign_key in Mongoid with belongs_to.

You CANNOT filter with the belongs_to like you can with ActiveRecord, but you can use scopes outside of the belongs_to to get the same effect. Exampe:

belongs_to :sensor
scope :for_year, -> (year) { where(:date.gte => Date.new(2015,1,1)).where(:date.lte => Date.new(2015, 12, 31))}

or

belongs_to :sensor
def self.for_year year
  where(:date.gte => Date.new(year,1,1)).where(:date.lte => Date.new(year, 12, 31))
end

So your query would become something like this:

sensor = Sensor.find_by(sensor_id: params[:sensor_id])
sensor.sensor_data.for_year(2015)