Ruby on Rails - Criteria - Mongoid - where condition with 2 by 2 columns - ruby

I'm working with RoR + MongoDB (Mongoid) and I need to apply a filter using or condition by 2 columns.
I saw some recommendations like this one but didn't work.
query = query.where(name: /#{attributes[:name]}/i).or(query.where(email: /#{attributes[:email]}/i))
If I use this one, looks like the or will be applied for all conditions:
query = query.where(name: /#{attributes[:name]}/i).or(email: /#{attributes[:email]}/i)
Anyone has any suggestion?

From what I understand the correct query should be:
query = query.or([{name: /#{attributes[:name]}/}, {email: /#{attributes[:email]}/i}])
This will return documents that has a name property with the value from attributes[:name] or documents that has email property with the value from attributes[:email]
Does this answer your question?

Related

How to use 'IN' opeartor in Spring boot & Couch base -N1QL query

I have a JSON list from which from which I 'm looking up for a particular value using N1QL query.
It works when I try only if there is only one value in the list.
But if there are multiple values in the list I'm not getting in response.
Json
"suppliers_list": [
"767",
"300767"
]
#Query("SELECT users.*, "
+ "META(users).id as _ID, META(users).cas as _CAS FROM #{#n1ql.bucket}"
+ "users WHERE lower(type)='users' AND ANY usersupplist IN users.suppliers_list SATISFIES usersupplist IN [$1] END")
userRepository.findBySupplierList(String List)
usersDefObjList = userRepository.findBySupplierList("767"); //Working
usersDefObjList = userRepository.findBySupplierList("767,300767"); // Not Working
usersDefObjList = userRepository.findBySupplierList("'767','300767'"); // Not Working
But the same one like works in CouchBase Query window
SELECT users.*,META(users).id as _ID,META(users).cas as _CAS FROM TCI_DATA_MIG users WHERE lower(type)='users' and ANY usersupplist IN users.suppliers_list SATISFIES usersupplist IN ['767','300767'] END
Please let me know your suggestions to get the values in the repository N1QL query to fix this.
In the N1QL right side of IN clause requires ARRAY.
If you know how many elements you can use
usersupplist IN [$1,$2,$3]
If the ARRAY is dynamic and don't know how many elements you can use following and pass in as ARRAY.
usersupplist IN $1
$1 = [ "767", "300767" ] i.e. JsonArray.from("767", "300767")
Check this out Couchbase parameterized N1QL query IN statement

Common part in associations rails, should I use merge?

Update 2
Cama::PostType.first.posts.joins(:custom_field_values)
.where("cama_custom_fields_relationships.custom_field_slug = ? AND
cama_custom_fields_relationships.value LIKE ?","localization",
"%Paris%").merge(Cama::PostType.first.posts.joins(:custom_field_values)
.where("cama_custom_fields_relationships.custom_field_slug = ? AND cama_custom_fields_relationships.value = ?","type-localization", "2"))
Why this merge doesn't work ?
It returns me same result when executed seperately... Merge should work as intersection so common part should be result. I dont get it
Update
I will try to ask in more conceptual way.
I have model B that have slug:text, value:text, belongs_to: Model A
I have model A that have name:string, has_many: Model B
#posts_one = I search for model B where slug="something", value = "city"
#posts_two = I search for model B where slug="mood", value="good"
I have 2 results based on diffrent parameters. Both belongs_to: model A
Now I want to return only the common belongs_to.
so if
#posts_one will return me 20 results with model_a_ids
#posts_two will return me 20 results with model_a_ids
I want to return only common model_a_ids of those 2 queries and right away to find posts. I try to make it in one query but dont know if its possible
Oryginal post
I use Camaleon CMS and I try to create filters based on additional "custom fields". I think to answer this question you dont have to know this cms.
I want to find common part of 2 queries or make it in one query(that would be the best)
I have
#posts = Cama::PostType.first.posts.includes(:custom_field_values)
#param_localization = "Paris"
#param_type_localization = "House"
#posts_one = #posts.merge(CamaleonCms::CustomFieldsRelationship.
where("cama_custom_fields_relationships.custom_field_slug = ? AND
LOWER(cama_custom_fields_relationships.value) LIKE ?", "localization",
"%#{#param_localization}%"))
puts #posts_one.count => 2
#posts_two = #posts.merge(CamaleonCms::CustomFieldsRelationship.where(custom_field_slug:
"type-localization", value: #param_type_localization))
puts #posts_two.count => 2
Question is how can I merge it together or make it one query ? When I made it in one where clause it returns me 0 results since I need to find 2 diffrent custom fields relationships that has diffrent values and slugs but it have relations to posts throught :custom_fields_values, so I have to make 2 queries I guess(like I did). First I find customFieldRelationship with slug = localization and second with slug = type_localization and then I need to find common part
I tried to #result = #posts_one.merge(#posts_two) but I got no result then. I thought it will return me "common part" of association which means 2 results
How can I combine it to find me posts that fullfil both queries ?
Let me know if I explained my problem not well enought.
You'll want to combine it in SQL: (untested)
#posts_combined = #posts.merge(CamaleonCms::CustomFieldsRelationship.
where("(cama_custom_fields_relationships.custom_field_slug = ?
OR cama_custom_fields_relationships.custom_field_slug = 'type-localization')
AND LOWER(cama_custom_fields_relationships.value) LIKE ? ", "localization",
"%#{#param_localization}%"))

How can we fetch column values which are between two limits in MongoTemplate?

for example i want to find age between 16 and 25 from a collection in mongoDB.
my query is..
Query query = new Query(Criteria.where("visibility").is(1)
.and("type").is("guide").and("age").gte(16).and("age").lte(25));
but it is giving exception. reason is mongo template do not support lte() and gte() with same column. so how can i handle it ? is their any solution ?
Try not to include an extra and("age") part in your criteria. What you need is this:
Query query = new Query(Criteria.where("visibility").is(1)
.and("type").is("guide").and("age").gte(16).lte(25));

Rails 4 and Mongoid: programmatically build query to search for different conditions on the same field

I'm building a advanced search functionality and, thanks to the help of some ruby fellows on SO, I've been already able to combine AND and OR conditions programmatically on different fields of the same class.
I ended up writing something similar to the accepted answer mentioned above, which I report here:
query = criteria.each_with_object({}) do |(field, values), query|
field = field.in if(values.is_a?(Array))
query[field] = values
end
MyClass.where(query)
Now, what might happen is that someone wants to search on a certain field with multiple criteria, something like:
"all the users where names contains 'abc' but not contains 'def'"
How would you write the query above?
Please note that I already have the regexes to do what I want to (see below), my question is mainly on how to combine them together.
#contains
Regex.new('.*' + val + '.*')
#not contains
Regex.new('^((?!'+ val +').)*$')
Thanks for your time!
* UPDATE *
I was playing with the console and this is working:
MyClass.where(name: /.*abc.*/).and(name: /^((?!def).)*$/)
My question remains: how do I do that programmatically? I shouldn't end up with more than two conditions on the same field but it's something I can't be sure of.
You could use an :$and operator to combine the individual queries:
MyClass.where(:$and => [
{ name: /.*abc.*/ },
{ name: /^((?!def).)*$/ }
])
That would change the overall query builder to something like this:
components = criteria.map do |field, value|
field = field.in if(value.is_a?(Array))
{ field => value }
end
query = components.length > 1 ? { :$and => components } : components.first
You build a list of the individual components and then, at the end, either combine them with :$and or, if there aren't enough components for :$and, just unwrap the single component and call that your query.

How and where to modify Magento search query?

First of all, I found similar questions in SO but there is not any answer for them. So, the first part of the question is a little bit duplicated. I want to improve search results in Magento. Here is what I've done already:
1. Search with AND instead of OR when there are multiple words.
2. Ajax search starts searching from anywhere and not only from the beginning of the fields.
3. Trim the last s from the words to prevent empty results when searching with plurals.
4. I changed the search type from Like to Fulltext or Combine but the results were not better and even were worst, so I leave it as is. It's Like now, so there is no relevance ordering.
The last thing which I want to try is adding this to the search query:
SELECT ... other non-full-text-cols
MATCH (product_title) AGAINST ('lean body for her') AS rel1,
MATCH (content) AGAINST ('lean body for her') AS rel2
FROM table
WHERE MATCH (product_title,content) AGAINST ('lean body for her')
ORDER BY (rel1*1.5)+(rel2)
Here is my query but I'm not sure if it would work because I can't test it:
$this->_productCollection->addAttributeToSelect(
array(
'rel1' => new Zend_Db_Expr('MATCH (name) AGAINST ("'.$queryText.'")'),
'rel2' => new Zend_Db_Expr('MATCH (short_description) AGAINST ("'.$queryText.'")')
)
);
$this->_productCollection->getSelect()
->where('MATCH (name,short_description) AGAINST ("'.$queryText.'")')
->order('(rel1*1.5)+(rel2)');
The main idea is to add bonus weight to a result if the search query is found in the title of the product. The problem is that I don't know where to modify the query. I can't find where it is at all. $this->_productCollection is not the right object, I know it. I looked at all the Collection.php files, resource models, models and even the query log but no luck. There are just little 1 or 2 row parts in some files but not a full query. I'm new to Magento and still have problems with finding this type of stuff. So, where I have to place my additional stuff when I have to extend a query?
Community Edition Magento, version 1.6.1.0.
Note: I know that some extension for improving search results will work much better than my solutions but for now I have to do it in that way. It would be a good experience for me, too.
Edit:
So, I figured out how to add my custom fields for the ordering but it's
untruly I think. In class Mage_CatalogSearch_Model_Layer extends Mage_Catalog_Model_Layer's prepareProductCollection method I added two joins to the query and get the fields rel1 and rel2:
$collection->getSelect()->joinLeft(
array('cpev' => 'catalog_product_entity_varchar'),
'cpev.entity_id = e.entity_id AND cpev.attribute_id = 96',
array('rel1' => new Zend_Db_Expr('2.01*(LENGTH(cpev.value) - LENGTH(REPLACE(LCASE(cpev.value), LCASE("'.$queryText.'"), ""))) / LENGTH("'.$queryText.'")'))
);
$collection->getSelect()->joinLeft(
array('cpet' => 'catalog_product_entity_text'),
'cpet.entity_id = e.entity_id AND cpet.attribute_id = 506',
array('rel2' => new Zend_Db_Expr('(LENGTH(cpet.value) - LENGTH(REPLACE(LCASE(cpet.value), LCASE("'.$queryText.'"), ""))) / LENGTH("'.$queryText.'")'))
);
I have these fields now but as you can see I have hard coded stuff like attribute_id = 96 etc. which is not good at all and it will not work everytime - I checked these ids directly from the database tables. I wrote it like this because I haven't access to name and short_description fields but they are in the result. Don't know why. So, cpev.value is name field and cpet.value is the short_description field. Moreover I can't order the results by these fields. I tried $collection->addOrder('SUM(rel1+rel2)');, $collection->getSelect()->order(new Zend_Db_Expr('SUM(rel1+rel2)').' DESC');, some addAttributeToFilter stuff etc. but it's not working.
Edit 2:
I accepted #james' answer but finally we bought an extension for improving the search results.
In Mage_CatalogSearch_Model_Resource_Fulltext check out prepareResult (line 310 in 1.7 CE) and look for the following:
$select->columns(array('relevance' => new Zend_Db_Expr(0)));
Magento sets all search result relevances as 0 (!); add the relevances you want (higher is better) here. You can create a custom query in Zend_Db_Expr() to generate higher relevances on attribute matches.
The answer to your first question (1):
To make an AND search instead of OR, you will need to rewrite the class
Mage_CatalogSearch_Model_Resource_Fulltext
In the method
public function prepareResult($object, $queryText, $query)
you want to switch the part
$likeCond = '(' . join(' OR ', $like) . ')';
to
$likeCond = '(' . join(' AND ', $like) . ')';
Be sure to reindex the search index afterwards to have an effect.

Resources