How can I retrieve a document by _id? - ruby

I'm trying to retrieve a document when I have an object id - however, the query does not work.
#collection = #db.collection('Mylist')
#result = #collection.find({"_id" => params[:id]})
I've tried variations of the query - it always yields empty - however when I try a query on the collection such as below, that would work.
#result = #collection.find({"Exist" => "True"})
Why? It is strange that complex queries work but a simple query by _id returns nothing.
If possible, I don't want to use MongoMapper.
Thanks

Found it - you need to wrap it like this -
find({"_id" => Mongo::ObjectId(params[:id])})

find(:_id => BSON::ObjectID(params[:id])

This would also work:
#coll.find_one(ObjectID.from_string(params[:id]))

Related

Rails update_all with hstore

What's a good way to update multiple records with hstore columns using activerecord? Right now I'm looping through, updating and saving like this:
time = Time.now.to_s
scoped_tasks.each do |task|
task.data[:last_checked] = time
task.save!
end
Is there any way to do this with an update_all query? One solution I've seen looks like this:
MyModel.update_all(:properties => ActiveRecord::Coders::Hstore.dump({'a' => 1}))
But the problem with that is it overwrites the entire column, so other values are lost. I've also seen this:
MyModel.update_all("data = data || hstore('a', 'blah')")
But for some reason I get back 0 for the value. It also looks like it will only work if the hstore is empty.
I struggled with the same question myself, here is how I was able to solve it:
MyModel.update_all([%(data = data || hstore(?,?)), 'a', 'new_value']))
The core fix for this was wrapping the update_all action in a [] and %(). I am still struggling to figure out how the %() defines the SET in the Postgre SQL so if anyone has an explanation that would be uber-helpful.
In my case I was actually removing a key too (really I wanted to update the key name but keep the value). So if anyone has that issue the code looks like:
MyModel.update_all([%(data = delete("data",?)), 'a'])
I was hoping to do both actions in the same call but that was creating a really odd command in the SQL where the second action was added as part of the WHERE clause not the SET. Still a bit of black magic for me but hopefully this helps...
If you use
MyModel.update_all(:properties => ActiveRecord::Coders::Hstore.dump({'a' => 1}))
then it will cleared out other values and if you try to use
MyModel.update_all("data = data || hstore('a', 'blah')") it will only work if there is any value in hstore column,
so try to use combination of both
if (hstore_column_name).present?
MyModel.update_all("data = data || hstore('a', 'blah')")
else
MyModel.update_all(:properties => ActiveRecord::Coders::Hstore.dump({'a' => 1}))

LINQ Query to filter results using where and lambda expression is returning wrong results

Filtering an IEnumerable result set using a where clause with condition is returning duplicate entries.
This is the query we are using to filter results. links is an IEnumerable with count 299. When the below query is executed, validLinks count is coming to 588, and each entry is duplicated. Please help us determine what is wrong with this query.
var validLinks = links.Where(link => link.Categories
.Where(category => category.!IsCatchAll)
.Any());
That code won't compile because the ! is in the wrong place. Also you don't need to do Where and Any. Try this:
var validLinks = links.Where(link => link.Categories.Any(category => !category.IsCatchAll);

How to exclude an array of ids from query in Rails (using ActiveRecord)?

I would like to perform an ActiveRecord query that returns all records except those records that have certain ids. The ids I would like excluded are stored in an array. So:
ids_to_exclude = [1,2,3]
array_without_excluded_ids = Item. ???
I'm not sure how to complete the second line.
Background: What I've already tried:
I'm not sure background is necessary, but I've already tried various combinations of .find and .where. For example:
array_without_excluded_ids = Item.find(:all, :conditions => { "id not IN (?)", ids_to_exclude })
array_without_excluded_ids = Item.where( "items.id not IN ?", ids_to_exclude)
These fail. This tip might be on the right track, but I have not succeeded in adapting it. Any help would be greatly appreciated.
Rails 4 solution:
ids_to_exclude = [1,2,3]
array_without_excluded_ids = Item.where.not(id: ids_to_exclude)
This should work:
ids_to_exclude = [1,2,3]
items_table = Arel::Table.new(:items)
array_without_excluded_ids = Item.where(items_table[:id].not_in ids_to_exclude)
And it's fully object-oriented with no strings :-)
You can also use Squeel gem to accomplish such query.
Documentation of it, goes here
As nslocum wrote, the following works well:
Item.where.not(id: ids_to_exclude)
If your "ids to exclude" come from a query (here with an example condition), you can even take it a step further:
Item.where.not(id: Item.where(condition: true))
This is useful if you need to filter another model:
OtherModel.where.not(item_id: Item.where(condition: true))

Retrieving array of ids in Mongoid

how do you retrieve an array of IDs in Mongoid?
arr=["id1","id2"]
User.where(:id=>arr)
You can do this easily if you are retrieving another attribute
User.where(:nickname.in=>["kk","ll"])
But I am wondering how to do this in mongoid -> this should be a very simple and common operation
Remember that the ID is stored as :_id and not :id . There is an id helper method, but when you do queries, you should use :_id:
User.where(:_id.in => arr)
Often I find it useful to get a list of ids to do complex queries, so I do something like:
user_ids = User.only(:_id).where(:foo => :bar).distinct(:_id)
Post.where(:user_id.in => user_ids)
Or simply:
arr = ['id1', 'id2', 'id3']
User.find(arr)
The above method suggested by browsersenior doesn't seem to work anymore, at least for me. What I do is:
User.criteria.id(arr)
user_ids = User.only(:_id).where(:foo => :bar).map(&:_id)
Post.where(:user_id.in => user_ids)
The solution above works fine when amount of users is small. But it will require a lot of memory while there are thousands of users.
User.only(:_id).where(:foo => :bar).map(&:_id)
will create a list of User objects with nil in each field except id.
The solution (for mongoid 2.5):
User.collection.master.where(:foo => :bar).to_a.map {|o| o['_id']}

LINQ Query to find all tags?

I have an application that manages documents called Notes. Like a blog, Notes can be searched for matches against one or more Tags, which are contained in a Note.Tags collection property. A Tag has Name and ID properties, and matches are made against the ID. A user can specify multiple tags to match against, in which case a Note must contain all Tags specified to match.
I have a very complex LINQ query to perform a Note search, with extension methods and looping. Quite frankly, it has a real code smell to it. I want to rewrite the query with something much simpler. I know that if I made the Tag a simple string, I could use something like this:
var matchingNotes = from n in myNotes
where n.Tags.All(tag => searchTags.Contains(tag))
Can I do something that simple if my model uses a Tag object with an ID? What would the query look like. Could it be written in fluent syntax? what would that look like?
I believe you can find notes that have the relevant tags in a single LINQ expression:
IQueryable<Note> query = ... // top part of query
query = query.Where(note => searchTags.All(st =>
note.Tags.Any(notetag => notetag.Id == st.Id)));
Unfortunately there is no “fluent syntax” equivalent for All and Any, so the best you can do there is
query = from note in query
where searchTags.All(st =>
note.Tags.Any(notetag => notetag.Id == st.Id))
select note;
which is not that much better either.
For starters see my comment; I suspect the query is wrong anyway! I would simplifiy it, by simply enforcing separately that each tag exists:
IQueryable<Note> query = ... // top part of query
foreach(var tagId in searchTagIds) {
var tmpId = tagId; // modified closures...
query = query.Where(note => note.Tags.Any(t => t.Id == tmpId));
}
This should have the net effect of enforcing all the tags specified are present and accounted for.
Timwi's solution works in most dialects of LINQ, but not in Linq to Entities. I did find a single-statement LINQ query that works, courtesy of ReSharper. Basically, I wrote a foreach block to do the search, and ReSharper offered to convert the block to a LINQ statement--I had no idea it could do this.
I let ReSharper perform the conversion, and here is what it gave me:
return searchTags.Aggregate<Tag, IQueryable<Note>>(DataStore.ObjectContext.Notes, (current, tag) => current.Where(n => n.Tags.Any(t => t.Id == tag.Id)).OrderBy(n => n.Title));
I read my Notes collection from a database, using Entity Framework 4. DataStore is the custom class I use to manage my EF4 connection; it holds the EF4 ObjectContext as a property.

Resources