Mongoid query in Rails: Can I find only those records which have embedded child objects? - ruby-on-rails-3

I would like to write a query in a Rails model using mongoid, and I'd like it to return only those records which have embedded child objects (in this case, client work links).
I only want to find clients which have embedded client work links.
This is what I'd like, though obviously it doesn't work because of the "where" parameters.
def self.latest_client_press
Work.where("!self.work_links.empty?").desc(:updated_at).limit(4)
end

While it is possible in MongoDB to query on array's size, this feature is rather limited.
What people do instead (and what is recommended on that page) is store array length along with the array itself. This way you can index this field and query documents very efficiently.

Related

Difference between ActiveRecord::Base.connection and find_by_sql

I need to perform some custom queries on my rails application and was wondering which approach is better:
results = ActiveRecord::Base.connection.execute(query)
Or
Model.find_by_sql(query)
Been reading the documentation but didn't really get how they perform.
execute is a low level method. It returns whatever the database driver returns, for example an instance of Mysql2::Result. You can execute any sort of query with this
find_by_sql returns an array of ActiveRecord objects of the appropriate class, constructed from the results (so it wouldn't make sense to pass a query that doesn't produce a suitable result set).
A halfway house are methods on connection such as select_all, select_values etc. These don't create active record objects, but do transform the raw driver results into arrays, hashes, strings etc.

How to query documents in MarkLogic and process results

I've been working off of the tutorial pages but seem to have a fundamental disconnect in my thinking transitioning off of RDBMS systems. I'm using MarkLogic and handling this database interaction through the Java API focusing on the search access via POJO method outlines in the tutorial documentation.
My reference up to this point has come from here principally: http://developer.marklogic.com/learn/java/processing-search-results
My scenario is this:
I have a series of documents. We'll call them 'books' for simplicity. I'm writing these books into my DB like this:
jsonDocMgr.write("/" + book.getID() + "/",
new StringHandle(
"{name: \""+book.getID()+"\","+
"chaps: "+ book.getNumChaps()+","+
"pages: "+ book.getNumPages()+","+
"}"));
What I want is to execute the following type of operation:
-Query all documents with the name "book*" (as ID is represented by book0, book1, book2, etc)
where chaps > 3. For these documents only, I want to modify the number of pages by reducing by half.
In an RDBMS, I'd use something like jdbcTemplate and get a result set for me to iterate through. For each iteration I'd know I was working with a single record (aka a book), parse the field values from the result set, make a note of the ID, then update the DB accordingly.
With MarkLogic, I'm awash in a sea of different handlers and managers...none of which seems to follow the pattern of the ResultSet with a cursor abstraction. Ultimately I want to do a two-step operation of check the chapter count then update the page field for that specific URI.
What's the most common approach to this? It seems like the most basic of operations...
Try the high-level Java API and see if it works for you. Create a multi-statement transaction with a query by example, then use document operations.
At a lower level, the closest match to a ResultSet is the ResultSequence class. The examples at http://docs.marklogic.com/javadoc/xcc/overview-summary.html are pretty good. For updates the interaction model between Java and MarkLogic is a bit different from JDBC and SQL. There is no SELECT... FOR UPDATE syntax.
The most efficient low-level technique is to select and update in one XQuery transaction, something like a stored procedure. However this requires good knowledge of XQuery. The other low-level approach is to use an XCC multi-statement transaction, which requires a little less knowledge of XQuery.
A minor issue in your code ... you definately do NOT want to end your JSON docuement URIs with "/" as you do in your sample code. You should end them with the ".json" or some other extension or no extension but definately not "/" as that is treated specially in the server.

ndb ComputedProperty filtering

I have a User ndb.Model which has a username StringProperty that allows upper en lower case letters, at some point I wanted to fetch users by username but have the case forced to lowercase for the filtering. Therefor I added a ComputedProperty to User: username_lower which returns the lowercase version of the username as follows:
#ndb.ComputedProperty
def username_lower(self):
return self.username.lower()
then I filter the query like so:
query = query.filter(User.username_lower==username_input.lower())
This works, however it only does for users created (put) after I added this to the model. Users created before don't get filtered by this query. I first thought the ComputedProperty wasn't working for the older users. However, tried this and calling .username_lower on an old user does work.
Finally, I found a solution to this is to fetch all users and just run a .put_multi(all_users)
So seems like a ComputedProperty added later to the model works when you invoke it straight but doesn't filter at first. Does it not get indexed automatically ? or could it be a caching thing.. ?
any insight to why it was behaving like this would be welcome
thanks
this is the expected behaviour. The value of a ComputedProperty (or any property for that matter I guess) is indexed when the object is "put". The datastore does not do automatic schema updates or anything like that. When you update your schema you need to either allow for different schema versions in your code or update your entities individually. In the case of changes to indexing you have no choice but to update your entities. The MapReduce API can be used for updating entities to avoid request limitations and the like.

Format Rails Query Strings by removing repitition /clients?ids[]=1&ids[]=2&ids[]=3

In Rails 3.1, how would you go about making a query string appear cleaner and more readable.
For example, the Rails default for a key with multiple parameters in the query string would appear like:
/clients?ids[]=1&ids[]=2&ids[]=3
I want it to appear like:
/clients?ids=1,2,3
or even
/clients?ids=1|2|3
The ids are controlled by a series of links that act as filters for selecting 1 or more options for filtering on some search results.
What would be the best way to go about this?
The only way you could do it automatically is by monkeypatching something in Rack or Rails. You should avoid doing that as it's going to cause more issues than it solves.
If you have a string that embeds a | or , then you could have it incorrectly converting data. Or if you only have one entry such as ids=1 it wouldn't know to convert it into an array with just 1 inside.
You would be better off doing this manually whenever you need to pass an array that needs to be cleaned up. In this case, you would just call ids.join(",") when passing it to the router method and params[:ids].split(",") to get an array back out.

not on a query in RoR

In Ruby on rails 3 I want to query on a has_many field of a model as follows:
#project.items.where(:status => 1)
The problem is I'm trying to get the exact opposite result than this. What i want is all items of #project where the status is not 1. Been looking for the answer to this for a while, anyone?
There are many ways to accomplish what you are trying to do, however, some are better than others. If you will always be searching for a hardcoded number (i.e. 1 in this case), then the following solution will work:
#project.items.where('status != 1')
However, if this value is not hard-coded, you are openly vulnerable to SQL injection as Rails will not (cannot) escape this kind of query. As a result, it is preferred among Rails developers to user the following syntax for most custom conditions (those that can't be constructed via Hash):
#project.items.where(['status != ?', 1])
This syntax is slightly confusing, so let me go over it. Basically you are providing the where clause an Array of values. The first value in the array is a String representing the query you want executed. Anywhere you want a value in that string, you place a ?. This serves as a placeholder. Next, you add an element for every question mark in you query. For example, if I had the following:
where(['first_name = ? AND last_name = ?', params[:first_name], params[:last_name]]
Rails will automatically match these up forming the query for you. In that process, it also escapes potentially unsafe characters, preventing injection.
In general, it is preferred to use the Array syntax, even for a hardcoded value. I've been told that pure string conditions in Rails 3.5 will raise a warning (unverified), so it doesn't hurt to get in the process of using the Array syntax now.