Ohm, find all records from array of ids - ruby-on-rails

I am looking for a way to find all Ohm affiliated objects with one query, by feeding it an array of attributes that are indexed. In Mongoid, this is done with something like:
Foo.any_in(:some_id => [list_of_ids])
ActiveRecord has the find_all family of methods.
I essentially want to be able to pull N records from the data store without calling find() 30 times individually.

You can pass find an array or list of IDs:
Foo.find(1,2,3) or Foo.find([1,2,3])

This does not seem to work with the latest Ohm (1.1.1). I looked through the source and it seems you need to do something like Model.all.send(:fetch, [1,2,3]). Problem is... you have to call a private method.
I created an issue to see if this is the right approach.
UPDATE: It was just made public!

Related

How can I disable lazy loading of active record queries?

I want to query some objects from the database using a WHERE clause similar to the following:
#monuments = Monument.where("... lots of SQL ...").limit(6)
Later on, in my view I use methods like #monuments.first, then I loop through #monuments, then I display #monuments.count.
When I look at the Rails console, I see that Rails queries the database multiple times, first with a limit of 1 (for #monuments.first), then with a limit of 6 (for looping through all of them), and finally it issues a count() query.
How can I tell ActiveRecord to only execute the query once? Just executing the query once with a limit of 6 should be enough to get all the data I need. Since the query is slow (80ms), repeating it costs a lot of time.
In your situation you'll want to trigger the query before you your call to first because while first is a method on Array, it's also a “finder method” on ActiveRecord objects that'll fetch the first record.
You can prompt this with any method that requires data to work with. I prefer using to_a since it's clear that we'll be dealing with an array after:
#moments = Moment.where(foo: true).to_a
# SQL Query Executed
#moments.first #=> (Array#first) <Moment #foo=true>
#moments.count #=> (Array#count) 42
In this case, you can also use first(6) in place of limit(6), which will also trigger the query. It may be less obvious to another developer on your team that this is intentional, however.
AFAIK, #monuments.first should not hit the db, I confirmed it on my console, maybe you have multiple instance with same variable or you are doing something else(which you haven't shared here), share the exact code and query and we might debug.
Since, ActiveRecord Collections acts as array, you can use array analogies to avoid querying the db.
Regarding first you can do,
#monuments[0]
Regarding the count, yes, it is a different query which hits the db, to avoid it you can use length as..
#monuments.length

Neo4j gem - Distinct Query with Paginate

How can I get my plucked array to work with the paginate method (which I believe only works on queryproxy objects)
My results are pulling up a few of the same nodes as there are multiple paths to it, so I added pluck and distinct like so..
current_user.friends....where()...params().pluck('DISTINCT e').paginate..
Is there another way around it? or would a change have to be made in the neo4j paginate gem?
Right now, this isn't doable using the paginate method. WillPaginate returns WillPaginate::Collection objects that are already populated from the database. We might be able to make it return something else and evaluate lazily but I'd have to play around with it more.
You can create Neo4j::Paginated objects directly, but these are just plucked results from QP.
# match stupid friends with awful events, return distinct events
query = current_user.friends(:f).where(stupid: true).events(e:).rel_where(expected_attendees: 0)
#bad_events = Neo4j::Paginated.create_from(query, 1, 15).pluck('distinct e')
create_from returns a Neo4j::Paginated object that delegates each and pluck to its the QueryProxy object fed to it. Note that it's going to paginate based on the end of the chain, so it's doing the first page with 15 per page based on the events. Also note that you can't do a distinct count.
Check https://github.com/neo4jrb/neo4j/blob/master/lib/neo4j/paginated.rb for more. It's pretty easy to read.

rails 4 activerecord relation pagination after filtering by permission

I'm using thinking sphinx as my search database, and after I search, I need to filter the results based off of if a user has access to see each result or not. I have a method like, current_user.can_see? that returns true/false. This works fine, however, no matter how I try to loop over the relation, it has to turn it into an array in order to filter/remove the results. This essentially breaks the pagination, total count, total pages, etc.
Does anyone know of a way to do this, or a different approach to paginating a filtered result set?
EDIT: Result set is coming back from a ThinkingSphinx search.
I assume you are using will_paginate.
When you have an array and not a collection, the only thing you have to do is to initialize in your app will_paginate in order to work for arrays.
You need to provide an initializer (for instance config/initializers/will_paginate.rb) that will only contain this line:
require 'will_paginate/array'
And there you go. It is working.

List of Model's Field in Rails

I've been looking at the Rails documentation and can't find this.
Lets say I have a Model User with field strength.
How do I get a list of all strengths for every instance of the model object in an array?
list_of_str = [1, 2, 3, 4, etc..]
I know that you can call User.all and iterate through each of their strength fields and append them to a list but is there a more elegant way of doing this?
User.pluck 'strength'
New in rails 3.2 if my memory is correct
You can use
User.uniq.pluck 'strength'
If you need to avoid duplicates, and you can also combine this with scopes and conditions, for example
User.where(...).pluck 'strength'
If you're really after the distinct strengths then:
User.select('distinct strength').pluck(:strength)
will get them. If you don't care about duplicates then Frederick Cheung's plain pluck would be a good idea.
You can use the select method for that, it generates a query where only the values of the desired field are retrieved (which is faster than loading all model data from the database):
User.select(:strength)
This still returns an array of model-objects, so you have to use map to get an array of the values only:
User.select(:strength).map(&:strength)
The creation of the model object will be slower than just querying the database for the values, but using raw SQL should be avoided if performance is not critical in this place.
Edit: There is an even better way (pluck), see the accepted answer.

why is Model.all different to Model.where('true') in rails 3

I have a query, which works fine:
ModelName.where('true')
I can chain this with other AR calls such as where, order etc. However when I use:
ModelName.all
I receive the "same" response but can't chain a where or order to it as it's an array rather than a AR collection.
Whereas I have no pragmatic problem using the first method it seems a bit ugly/unnecessary. Is there a cleaner way of doing this maybe a .to_active_record_collection or something?
There is an easy solution. Instead of using
ModelName.where('true')
Use:
ModelName.scoped
As you said:
ModelName.where('true').class #=> ActiveRecord::Relation
ModelName.all.class #=> Array
So you can make as many lazy loading as long as you don't use all, first or last which trigger the query.
It's important to catch these differences when you consider caching.
Still I can't understand what kind of situation could lead you to something like:
ModelName.all.where(foobar)
... Unless you need the whole bunch of assets for one purpose and get it loaded from the database and need a subset of it to other purposes. For this kind of situation, you'd need to use ruby's Array filtering methods.
Sidenote:
ModelName.all
should never be used, it's an anti-pattern since you don' control how many items you'll retrieve. And hopefully:
ModelName.limit(20).class #=> ActiveRecord::Relation
As you said, the latter returns an array of elements, while the former is an ActiveRecord::Relation. You can order and filter array using Ruby methods. For example, to sort by id you can call sort_by(&:id). To filter elements you can call select or reject. For ActiveRecord::Relation you can chain where or order to it, as you said.
The difference is where the sorting and processing goes. For Array, it is done by the application; for Relation - by the database. The latter is usually faster, when there is more records. It is also more memory efficient.

Resources