Rails3 Arel Building the Where Clause - ruby-on-rails-3

I'm trying to build the where clause using AREL but this does not execute the query:
rec = self.where('color' => color_passed)
rec = rec.where('make' => make_passed) if make_passed.present?
rec = rec.where('year' => year_passed) if year_passed.present?
How can I correctly append the where conditions based on some conditions?

What do you mean not execute? where only return a Relation object, you have to call all to get the result:
rec.all

Related

Wrong group query when trying to build dynamically

I am trying to working on a query builder and the example/content is just imaginary.
query = from en in Data.InfectionRevision
query = from q in query, select: map(q, [:is_complete, :is_active])
query = from(q in query,select_merge: %{"$aggregate": %{"$max": %{^"revision_id" => max(q.revision_id)}}})
query = from(q in query,group_by: q.encounter_id,
select_merge: %{"$group" => %{^"encounter_id" => q.encounter_id}})
But the query I get is having incorrect key for group, although I have passed correct key while building query. this is what I got
#Ecto.Query<from i0 in Data.InfectionRevision, group_by: [i0.encounter_id],
select: merge(merge(
map(i0, [:is_complete, :is_active]),
%{"$aggregate": %{"$max": %{^"revision_id" => max(i0.revision_id)}}}),
%{"$group" => %{^"revision_id" => i0.encounter_id}})>
%{"$group" => %{^"revision_id" => i0.encounter_id}} should be actually %{"$group" => %{^"encounter_id" => i0.encounter_id}}
What Step or part of the query I am building wrong? How to fix it?
Note:
sample project on which you can run/build above queries
Please ignore the query content, it might not makes sense because its just an example and should work dynamically as its part of dynamic query builder
I need to build query step by step from passed params dynamically

CakePHP - add custom SQL to a Query object

I'm using CakePHP 3.5.13 to build an application which has 4 separate databases.
The main database (Datasource default in config/app.php) for the application has been baked. It was a legacy database, and the naming conventions are not written according to the way CakePHP specifies. Nonetheless it works, after going through the Models and editing things.
In a controller I have the following:
$substances = TableRegistry::get('Substances');
$query = $substances->find()->limit(250)->offset(0);
$query->select(['id', 'app_id', 'name']);
$query->contain([
'Cas' => [
'sort' => ['Cas.id' => 'ASC']
]
]);
$query->contain([
'Ecs' => [
'sort' => ['Ecs.id' => 'ASC']
]
]);
If I var_dump($query) I get an SQL string as follows:
SELECT Substances.id AS `Substances__id`,
Substances.app_id AS `Substances__app_id`,
Substances.name AS `Substances__name`
FROM substances Substances LIMIT 250 OFFSET 0
I need to modify this so the query contains an INNER JOIN to a table which is stored in one of the other databases (Datasource sdb5_tmpdata in config/app.php). The SQL I need is as follows:
SELECT Substances.id AS `Substances__id`,
Substances.app_id AS `Substances__app_id`,
Substances.name AS `Substances__name`,
Substances.date AS `Substances__date`
FROM substances Substances
INNER JOIN `sdb5_tmpdata`.`searching_1745` AS tf
ON tf.id = Substances.id LIMIT 250 OFFSET 0;
The difference between the above query and original is the following SQL:
INNER JOIN `sdb5_tmpdata`.`searching_1745` AS tf
ON tf.id = Substances.id
I don't have a corresponding Model for the table 'searching_1745' because these tables are dynamically created (and later dropped) on a database which holds "temporary" user data.
Is it possible to modify the query object, $query, such that I can introduce the custom SQL that does the inner join?
I have tried $query = $query->newExpr()->add('INNER JOIN 'sdb5_tmpdata'.'searching_1745' AS tf ON tf.id = Substances.id'); but it doesn't work.
the query builder let you build the query as you like it. It does not matter if you don't have a Table Object for that table
$query->join([
'tf ' => [
'table' => 'sdb5_tmpdata.searching_1745',
'type' => 'INNER',
'conditions' => 'tf.id = Substances.id',
]);
see here
I don't know if you can modify the query object, but tou can always write your own custom queries:
use Cake\Datasource\ConnectionManager;
$conn = ConnectionManager::get('default');
$query = $conn->query('query goes here');
for more info, read: https://book.cakephp.org/3.0/en/orm/database-basics.html#executing-queries

How can I use a method to add a filter on a property in Entity Framework Core?

I need to conditionally add a filter to particular dates in a query. There are common preconditions and the filter will be the same. Therefore I would like the common code to be in a method which can perform these checks and then have the consumer pass in the property which the filter should be applied to (could be applied to multiple).
Here is a simplified version of my code.
var query = dbContext.Documents.AsQueryable();
query = FilterDocumentsByDate(query, x => x.CreatedDate);
query = FilterDocumentsByDate(query, x => x.SubmittedDate);
private IQueryable<Document> FilterDocumentsByDate(IQueryable<Document> query, Func<Document, DateTime> propertyToSearch)
{
query = query.Where(x => propertyToSearch(x).Year > 2000);
return query;
}
When I look at the query in SQL profiler, I can see that the query is missing the WHERE clause (so all documents are being retrieved and the filter is being done in memory). If I copy/paste the code inline for both dates (instead of calling the method twice) then the WHERE clause for the both dates are included in the query.
Is there no way to add a WHERE condition to an IQueryable by passing a property in a Func which can be properly translated to SQL by Entity Framework?
EF is unable to understand your query, so it breaks and executes WHERE clause in memory.
The solution is creating dynamic expressions.
var query = dbContext.Documents.AsQueryable();
query = FilterDocumentsByDate(query, x => x.CreatedDate.Year);
query = FilterDocumentsByDate(query, x => x.SubmittedDate.Year);
private IQueryable<Document> FilterDocumentsByDate(IQueryable<Document> query, Expression<Func<Document, int>> expression)
{
var parameter = expression.Parameters.FirstOrDefault();
Expression comparisonExpression = Expression.Equal(expression.Body, Expression.Constant(2000));
Expression<Func<Document, bool>> exp = Expression.Lambda<Func<Document, bool>>(comparisonExpression, parameter);
query = query.Where(exp);
return query;
}
I am sorry, I haven't run this myself, but this should create WHERE statement. Let me know how it goes.

Querying distinct with MongoMapper

How do I query distinct with MongoMapper? My query is:
subscribedToThread = Comment.where(:subscribe_thread => 1).all
But this will return many objects with the same user_id. I need to return just a distinct user_id. Is this possible?
I think you will need to drop down to the ruby driver in order to do this as I don't think you can do this with MongoMapper itself:
subscribedToThread = Comment.collection.distinct("user_id", {:subscribe_thread => 1})
Calling the collection method on a model returns the collection as would be provided by the Ruby driver directly so you can issue a distinct query using the syntax below:
collection.distinct(key, query = nil)
You can read more about it here
Yes, you can do so:
subscribedToThread = Comment.where(:subscribe_thread => 1).fields(:user_id).all.compact!.unique!
This will nil every field but user_id which you then uniq!,ie you remove all doubles and then compact! all nil
http://mongomapper.com/documentation/plugins/querying.html#fields
Try this
subscribedToThread = Comment.where(:subscribe_thread => 1).fields(:user_id).collect(&:user_id).uniq
It will show you list of uniq user_id

rails/activerecord: how to get SQL COUNT and SUM to work with Postgres (at heroku)

My rails 3 app needs to use a SELECT DISTINCT which (as far as I know) cannot be done with activerecord queries. So I have been executing direct SQL and it is running fine locally on sqllite -- But it is failing at Heroku (postgres).
In my local (sqllite) app, this works fine:
r = ActiveRecord::Base.connection.execute("my query string")
But on heroku, using ActiveRecord::Base.connection.execute ALWAYS returns an empty dataset
#<PGresult:0x0000000xxxxxxxxx>
even for very simple queries such as
r = ActiveRecord::Base.connection.execute("SELECT numeric_score FROM beeps WHERE store_id = '132' AND survey_num = '2'")
So I'm using heroku console to debug some very basic SQL queries to try to understand how to re-format my SQL to work at Heroku/Postgres.
SELECT column_name WORKS: the heroku console, selecting postgres records is no problem, for example this works fine:
n = Beep.find_by_sql("SELECT numeric_score FROM beeps WHERE store_id = '132' AND survey_num = '2'")
gives the three values expected:
[#<Beep numeric_score: 10>, #<Beep numeric_score: 9>, #<Beep numeric_score: 8>]
But SELECT COUNT fails?? When I try to COUNT them in the SQL
n = Beep.find_by_sql("SELECT COUNT(*) FROM beeps WHERE store_id = '132' AND survey_num = '2'")
it fails, giving:
[#<Beep >]
And SELECT SUM(column) fails too?? When I try to SUM them
n = Beep.find_by_sql("SELECT SUM(numeric_score) FROM beeps WHERE store_id = '132' AND survey_num = '2'")
it also fails, giving:
[#<Beep >]
How do I execute direct SQL with Postgres... SUM(columnname) and COUNT(*) should work, right?
There's a couple of things here.
Firstly, find_by_sql will return initialised objects based on the data coming back, which is why you're not seeing anything coming back from your counts.
In order to do this with AR you can do:
Beep.where(:store_id => 123).where(:survey_num => 2).count
=> 5
This will return a number. It's the same with sums:
Beep.where(:store_id => 123).where(:survey_num => 2).sum(:numeric_score)
=> 5
You can also use distinction with AR, but it's not as clean:
Beep.select("DISTINCT *").where(:store_id => 123).where(:survey_num => 2)
=> [<Beep>, <Beep>...etc]
In order to query the db directly, this is still possible, and you were almost there:
conn = ActiveRecord::Base.connection
sql = "SELECT DISTINCT * FROM beeps WHERE store_ID = 123"
res = conn.execute sql
# res is now a PGResult object
res.each do |row|
puts row["id"]
puts row["numeric_score"]
end
There's a uniq method that you can add on to your ActiveRecord relation that adds DISTINCT to the SELECT.
Beep.where(:store_id => 123).where(:survey_num => 2).uniq
See also: http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-uniq