简体   繁体   English

搜索多个表并将结果添加到数组

[英]Search multiple tables and add results to array

As an exercise I was given a project with three tables Booking, Room and Host. 作为一个练习,我得到了一个包含三个表Booking,Room和Host的项目。 The models are as follows: 这些模型如下:

class Booking < ActiveRecord::Base
  belongs_to :room
end

class Room < ActiveRecord::Base
  belongs_to :host
  has_many :bookings
end

class Host < ActiveRecord::Base
  has_many :rooms
end

The database schema looks like this: 数据库模式如下所示:

ActiveRecord::Schema.define(version: 20150305133000) do

  create_table "bookings", force: true do |t|
    t.integer  "room_id",          null: false
    t.date     "start_date",       null: false
    t.date     "end_date",         null: false
    t.integer  "number_of_guests", null: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "hosts", force: true do |t|
    t.string   "name"
    t.string   "address"
    t.string   "picture_url"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "rooms", force: true do |t|
    t.integer  "host_id",    null: false
    t.integer  "capacity",   null: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

end

I need to implement a search feature that returns all hosts with rooms available between dates specified by the search form. 我需要实现一个搜索功能,该功能将返回所有主机,并在搜索表单指定的日期之间提供可用的房间。 To find hosts that are available for the required dates I need to cross reference with the Bookings table. 要查找在所需日期可用的主机,我需要与“预订”表进行交叉引用。

I skimmed through the ruby guides and also had a look at this question but I'm having trouble implementing what I've read. 我浏览了红宝石指南 ,也浏览了这个问题,但是我很难实现所阅读的内容。

In the rails console I've been playing around with varying queries to try and get the results I need. 在Rails控制台中,我一直在尝试各种查询以尝试获取所需的结果。

If I let @bookings = Booking.includes(:room).all and @hosts = [] and if start_date , end_date and guests are parameters returned from he search then running the following query: 如果我让@bookings = Booking.includes(:room).all @hosts = []@hosts = []并且如果start_dateend_dateguests是他搜索返回的参数,则运行以下查询:

@bookings.each { |b| @hosts.push(b.room.host) if (b.start_date < start_date && b.end_date > end_date && (b.room.capacity - b.number_of_guests >= guests)) }

produces an empty @hosts . 产生一个空的@hosts I then tried 然后我尝试了

 Booking.joins(:room).where("start_date < ? AND end_date > ? and capacity-number_of_guests >= ?", start_date, end_date, guests)

But that also returned and empty response so then I tried to do this in baby steps by finding all the bookings for the requested dates, filtering out the rooms that didn't have any space and then gathering together all the hosts of the rooms that were left. 但这也返回了空的响应,因此我尝试着一步一步地找到所需日期的所有预订,过滤掉没有空间的房间,然后将所有房间的主机聚集在一起剩下。 I got as far as: 我得到了:

@bookings = Booking.where("start_date = ? AND end_date >= ?",
  Date.parse(params[:start_date]),
  Date.parse(params[:end_date])).paginate(:page => params[:page], :per_page => 10)

@bookings.reject{ |booking| (booking.room.capacity - booking.number_of_guests) == 0 }

However, this is still returning empty rooms. 但是,这仍在返回空房间。 I've been at this for over a day now so if anyone can point me in the right direction towards getting this solved I'd appreciate it! 我已经在这里待了一天,所以如果有人能指出正确的方向来解决这个问题,我将不胜感激!

DEBUGGING ATTEMPTS 调试尝试

Following denis-bu's suggestions I've updated my first query to read (leaving the room capacity alone for the time being): 遵循denis-bu的建议,我已经更新了我的第一个查询以使其读取(暂时不留房间容量):

@bookings.each { |b| @hosts.push(b.room.host) if ((b.start_date > start_date &&
  b.start_date < end_date) || (b.end_date > start_date && b.end_date < end_date)) }

I've run this in the rails console and when I then try @hosts.count it returns 0 - so that implies the query isn't fetching any results. 我已经在rails控制台中运行了它,然后当我尝试@hosts.count它返回0这意味着该查询未获取任何结果。 I'd expect to see an array of Host records. 我希望看到一系列Host记录。

With my Where Exists gem and PostgreSQL: 使用我的《 Where Exists》 gem和PostgreSQL:

Room.includes(:host).where_not_exists(:bookings,
 [
   "(?, ?) OVERLAPS (start_date, end_date)",
   params[:start_date],
   params[:end_date]
 ]
)

Without the gem: 没有宝石:

# Using PostgreSQL OVERLAPS (http://www.postgresql.org/docs/9.0/static/functions-datetime.html)

overlaps = Booking.where(where("(?, ?) OVERLAPS (start_date, end_date)", start_date, end_date))

# With MySQL or SQLite you should check for boundaries manually

overlaps = Booking.where("? < end_date", start_date).where("? > start_date", end_date)

Room.includes(:host).where("NOT EXISTS (#{
  overlaps.where("bookings.room_id = rooms.id").to_sql
})")

It's not really enough details of what you're trying to achieve, but I'd make a guess that prolem is with your condition: start_date < ? AND end_date > ? 关于您要实现的目标的详细信息还不够多,但是我猜测问题与您的条件有关: start_date < ? AND end_date > ? start_date < ? AND end_date > ? - checks that query dates within booking interval, instead you should check that booking overlaps with your query dates: ((b.start_date > START_DATE and b.start_date < END_DATE) OR (b.end_date > START_DATE and b.end_date < END) . -检查查询日期是否在预订间隔内,而应该检查预订是否与查询日期重叠: ((b.start_date > START_DATE and b.start_date < END_DATE) OR (b.end_date > START_DATE and b.end_date < END)

BUT, I'd say that is not all you should do. 但是,我想这不是您应该做的所有事情。 You should also find rooms without bookings for query dates and then union those sets. 您还应该找到没有预订的房间以查询日期,然后合并这些集合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM