thinking sphinx date range problem - ruby-on-rails

Why does this return results:
#results = Index.search "#{#keywords}", :with => {
:published_on => 1.week.ago..Time.now,
}
but not this?
#results = Index.search "#{#keywords}", :with => {
:published_on => '2011-04-01'..'2011-04-08',
}
published_on is a datetime field, but I have tried it with hour, minutes and seconds as well.

Given you're getting results, I'm guessing published_on is actually an attribute, not a field?
If the attribute is a datetime data type, then you need to pass in Ruby Time objects for filters - that, or integer timestamps (which is what Thinking Sphinx converts times to anyway). TS doesn't try to parse strings, so you'll need to manage that yourself.
Sphinx isn't as fancy as MySQL when it comes to auto-parsing dates and times - you need to use the right data type.

Related

comparison Operators in thinking Sphinix

I have a model with attributes start_date and end_date. I have search form where user will put the date and I should get a data from the model if date is in between start_date and end_date.
how should I create a query with thinking sphinx.
You will need to do something like the following:
Add both start_date and end_date as attributes (not fields) to your model's Sphinx index.
Translate form params into a date or time value
Use range filters to limit search queries.
I've opted for very large windows of time, but essentially this ensures the given date is equal to or larger than the start date and less than or equal to the end date.
beginning, ending = Time.utc(1970), Time.utc(2030)
Model.search :with => {
:start_date => beginning..date_from_params,
:end_date => date_from_params..ending
}

Query based on calculated fields with Mongoid

I want to implement a scope overdue in a model Invoice to return all invoices that exceeded the date, until they had to be paid. I have the fields invoice_date, :type => Date and days_for_payment, :type => Integer.
In my previous version, which was built on ActiveRecord, I could use the query
Invoice.where("invoice_date + days_for_payment < ?", Date.today)
This query made the calculation on the DB side.
Is there a way to get the same thing done with Mongoid? Or does anyone know a good workaround (proc, lambda, etc.)?
I use mongoid '2.4.12'
Found the answer myself. With the prefix this.* I can reference to the fields. And I can use JavaScript functions. MongoDB gets cooler and cooler!
So here is my solution:
class Invoice
include Mongoid::Document
field :invoice_date, :type => Date
field :days_for_payment, :type => Integer
...
scope :overdue, where("(Math.round(this.invoice_date.getTime() / 1000) + (this.days_for_payment * 24 * 3600)) < #{Time.now.to_i}")
...
end
Timestamp creation in js works different. So I had to get rid of the last three numbers and round them.
If anybody knows a more elegant way, please let me know.
My only problem left is, that I can't store a Date object to MongoDB. It always tells me I have to use Time. I think I better upgrade mongoid to 3.0.1.
I am not sure about mongoid, if you are querying mongodb directly you can use the $where operator. It is not recommended as it doesn't use indexes. If you have another condition that filters the records to a small set then you can use the $where to further filter it.

How do I get the search to use the attr_accessor?

Ok so i have a date field that i need to search on, but i need to search on it by day like in a mysql query
search_conditions << ["DAY(open_date) != ?", event.thursday.day] if options[:thur].blank?
and i need to do this condition with Thinking Sphinx so i tried this
attr_accessor :event_day
def event_day
self.start_date.day
end
#thinking sphinx configurations for the event search
define_index do
indexes event_day
...
...
and in the search i tried this
search_string = "#event_day -#{event.thursday.day}" unless options[:thur].blank?
but i keep getting this error
index event_core: query error: no field 'event_day' found in schema
Any way to make this work
You can't use a ruby attribute in an SQL query. Rails isn't that clever.
You need to write SQL that replicates that function, or filter the results of a query through it, e.g.
#my_query.where(:a => "b").select { |rec| rec.some_method == "some value" }
As Michael's pointed out, Ruby attributes aren't accessible by Sphinx - it talks directly to your database.
So, either you can create a column that holds the event day value, and reference that via Sphinx, or you can create a field that uses a SQL function (which could vary, depending on MySQL or PostgreSQL) that extracts the day from the start_date column - not particularly complex. It'd probably end up looking like this:
indexes "GET_DAY_FROM_DATE(start_date)", :as => :event_day

How to use datetime in the condtions of a find/count in Ruby on Rails

I'm trying to count the number of rows in a certain table by datetime.
More specifically, by a certain month, but can't find the right way to
write the conditions for it.
xxx.count(:all, :conditions=> :xxx => yyy)
I have a datetime yyy to compare with xxx, but only want to compare the year and month.
The more efficient way is like this:
range = Date.today.beginning_of_month..Date.today.end_of_month
Model.count(:conditions => {:date_field => range})
This will generate a range condition, which, if you have an index on the date_field will be very fast even for millions of rows.
I have a plugin/gem called by_star which you can install using just sudo gem install by_star if you have gemcutter.org as one of your sources.
This plugin allows you to do this:
Post.by_month("January", :year => 2009)
Which will return all records from the Post model from January 2009.
This might work.
:conditions => ["month(date_field) = ? AND year(date_field) = ?", month, year]

Filtering Sphinx search results by date range

I have Widget.title, Widget.publish_ at, and Widget.unpublish_ at. It's a rails app with thinking_sphinx running, indexing once a night. I want to find all Widgets that have 'foo' in the title, and are published (publish _at < Time.now, unpublish _at > Time.now).
To get pagination to work properly, I really want to do this in a sphinx query. I have
'has :publish_at, :unpublish_at' to get the attributes, but what's the syntax for 'Widget.search("foo #publish_ at > #{Time.now}",:match _mode=>:extended'? Is this even possible?
Yep, easily possible, just make sure you're covering the times in your indexes:
class Widget < ActiveRecord::Base
define_index do
indexes title
has publish_at
has unpublish_at
...
end
To pull it based purely off the dates, a small amount of trickery is required due to sphinx requiring a bounded range (x..y as opposed to x>=y). The use of min/max value is very inelegant, but I'm not aware of a good way around it at the moment.
min_time = Time.now.advance(:years => -10)
max_time = Time.now.advance(:years => 10)
title = "foo"
Widget.search title, :with => {:publish_at => min_time..Time.now, :unpublish_at => Time.now..max_time}
I haven't used sphinx with rails yet.
But this is possible by the Sphinx API.
What you need to do is to set a datetime attribute at your sphinx.conf.
And don't forget to use UNIX_TIMESTAMP(publish_at), UNIX_TIMESTAMP(unpublish_at) at your index select.

Resources