Using thinking_sphinx to fetch data from records. It working fine but facing an issue that not find any to get records on date comparison like created_at greater than or less than. I check their official documentation also Thinking Sphinx
Is thinking sphinx provide that way? If yes then can we do that
It is possible, but it's not entirely obvious.
What you'll need to do is add an extra column in the SELECT clause, and then filter by that. Something along the lines of:
Model.search "pancakes",
:select => "*, IF(created_at > #{1.year.ago.to_i}, 1, 0) AS time_match",
:with => {:time_match => 1}
You will need to have created_at as an attribute in your index file for this to work.
Related
I have two models user and orders.
I have one in User model as has_many orders.
I am creating one index in thinking sphinx like :
has association(:created_at), as: :order_time, type: :timestamp
Now I want to search for users who have created any order in some time range. and using above index as
User.search with: {:order_time => t1..t2}
But, this is not giving accurate results. Any idea what am I doing wrong here.
Also I tried writing a sql query also something like
user_order_time = <<-SQL
SELECT orders.created_at
FROM orders
WHERE (orders.creator_id = users.id)
SQL
and added index in this way
has "#{user_order_time}", as: :order_time, type: :timestamp
and tries to use this index, even this isn't working.
Can anyone tell me the problem with each approach.
Firstly, this answer is written presuming you're using SQL-backed indices (using the :with => :active_record option in your index definition) rather than real-time indices, and you're using Thinking Sphinx v3.
To cover your second approach first:
user_order_time = <<-SQL SELECT orders.created_at FROM orders WHERE (orders.creator_id = users.id) SQL
has "#{user_order_time}", as: :order_time, type: :timestamp
This will not work. You can refer to SQL snippets in attributes and fields, but only the sections that go in the SELECT clause. You cannot use full SQL queries.
However, with this approach, you're on the right track:
has association(:created_at), as: :order_time, type: :timestamp
Are you using association there just when writing this question, not in your actual code? Because it should be something like this:
has orders.created_at, as: :order_time
I've not specified the type - Thinking Sphinx will automatically detect this from the database.
If that doesn't work, it's worth looking at the generated SQL query in the Sphinx configuration file for clues as to why it's not returning the values you're expecting (locally, that's config/development.sphinx.conf, and you're looking for the sql_query setting in source user_core_0).
I would like to know which method is fastest for return a record.
Class.where(:type => 4).first
Class.find(:first, :conditions => ["type = ?", 4])
Is the execution exactly the same?
The most performant, assuming you don't care about the order, is to use find_by:
Class.find_by(type: 4)
From https://github.com/rubocop-hq/rails-style-guide/issues/76
This method has been added on Rails 4 and it is defined like this:
def find_by(*args)
where(*args).take
end
So, take differs from first in regards to the order of your records. first will return the first record according to the order of the primary key while take will just return whatever the database spits out first.
So while using where().take is equivalent to find_by and choosing whether to use one of the other is a matter of taste, where().first differs from find_by in a subtle and not so obvious way.
Both would produce the same query.
According to the latest information, under Rails 3.1, passing in :conditions will be deprecated.
Hence, right now, the best way to execute the query is to use:
Class.where(:type => 4).first
I'm not sure who is at fault here, but we have a column in our users table called last_logged_in_at that we use for sorting. This is in a Rails 2.3 project using Thinking Sphinx with delta indexes enabled.
When a record has delta set to true, it is push to the bottom even if the sorting by last_logged_in_at should put it at the top.
I tried with last_logged_in_at being a datetime, a timestamp and even an integer and the behavior is always the same.
Any ideas why?
The query looks something like:
{:populate=>true,
:match_mode=>:boolean,
:order=>"last_logged_in_at DESC, updated_at DESC",
:per_page=>20,
:with_all=>{:role_id=>17,
:state=>"activated",
:mandator_id=>9,
:profile_active=>true},
:page=>nil}
Sorry, life's crazy busy, hence slow reply.
You're filtering on a string - which Sphinx doesn't currently allow. There are ways around this, though.
Also: You're using :with_all, but :with behaves in exactly the same way in your situation. :with_all is useful when you want to match multiple values on a single attribute. For example, this query will match results where articles have any of the given tag ids:
Article.search :with => {:tag_ids => [1, 2, 3]}
But this next query matches articles with all of the given tag ids:
Article.search :with_all => {:tag_ids => [1, 2, 3]}
I realise neither of these points are directly related to your issue - however, it's best to get the query valid first, and then double-check whether the behaviour is correct or not.
So I have two separate queries:
tagged_items = Item.tagged_with(params[:s], :on => :tags)
searched_items = Item.find(:all, :conditions => ["MATCH(title) AGAINST (? IN BOOLEAN MODE)", "*#{params[:s]}*"])
The first tagged_items is using the acts_as_taggable_on plugin to find all the items tagged with XYZ.
The second, searched_items, is used to search the items table for the search term.
So, how could I combine (and avoid duplicates) the results of these two?
Check out named_scope. The second query can be converted to named_scope easily, I'm not sure about the first one, but if you can rewrite it using find, you're home.
http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html
items = (tagged_items + searched_items).unique
But it would be much better if you could fetch them with single query.
This approach...
#items = tagged_items | searched_items
...would make more sense if you're looking to use the results of these queries in a View, instead of working with an Array, and accomplishes the de-duplication as well.
Let's assume I have a model called "product." Let's assume that product has three fields. These fields are 'name' (type string), 'cost' (type integer), and 'is_visible' (type bool).
1) How can I do a search query using the Rails "find" method (if there is another method, that's fine) so that I can search for all products with a cost greater than 100 AND is_visible is true?
2) What if we wanted to change this to search to where name != '' OR cost == 0?
This isn't a problem to do an SQL, but I would like to think that Rails has a way to do AND/OR queries to the database without using SQL.
Thanks!
You would need to use the conditions option on the find method. The conditions option can be either a Hash, Array, or String. There are lots of options for conditions, so I recommend reading the API help for it.
For example if you want to (1):
Product.find(:all, :conditions => ['cost > ? and is_visible is true', 100])
Or (2)
Product.find(:all, :conditions => ["name != '' or cost =0])
If you want something like LINQ you can check alternative Ruby ORMs like DataMapper or Sequel that provide more complex filtering capabilities.
For example in Sequel 2 you can write:
items.filter((:cost > 100) & (:is_visible = 1))
You can also use the bitwise "|" operator to get OR condition.
In DataMapper this will look like:
Model.all(:cost.gt => 100, :is_visible.eq => 1)
However some people don't like the fact that those features are implemented by overloading the standard Symbol class.
This is exactly the problem SQL was designed to solve, so why not to use it? Just add an appropriate :condition and your problem is solved.