I want to query with mongoid , I have following models
class Score
include Mongoid::Document
field :value, :type => Integer
belongs_to :user
end
class User
include Mongoid::Document
field :name, :type => String
field :age, :type => Integer
has_many :scores
I want to query all the scores from collection with their users. but users object should have only have the 'name' field in it
I would be something like
Score.find.all.includes(:user).only(:name)
Please tell the correct syntax for this
Score references User, so it is not possible to retrieve them both in one query, because there are no joins in MongoDB.
Either denormalize and include user name in Score or do several queries.
Related
Work env: Rails 4.2 mongoid 5.1
Below are my models:
class Tag
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
belongs_to :entity_tags, :polymorphic => true
end
class EntityTag
include Mongoid::Document
include Mongoid::Timestamps
field :tag_id, type: String
field :entity_id, type: String // Entity could be Look or Article
field :entity_type, type: String // Entity could be Look or Article
field :score, type: Float
end
class Look
include Mongoid::Document
include Mongoid::Timestamps
has_many :tags, :as => :entity_tags
end
class Article
include Mongoid::Document
include Mongoid::Timestamps
has_many :tags, :as => :entity_tags
end
We are trying to implement polymorphic functionality between Looks and Articles to Tags.
i.e. Let's say we have a Tag named "politics", and we would like to add the tag to an Article with the score '0.9' and to a Look with the score '0.6'. The Score should be saved at the EntityTags Model.
The problem:
The first assign of the tag works, but then when I try to assign the same tag to another entity, it removes it and reassigns it from the first one to the latter.
The assignment looks like the following:
entity.tags << tag
Does anybody know the proper way to save associations and create the EntityTag Object with the correct polymorphism and assignment properly?
Thanks!
I've managed to implement a non-elegant working solution based on the following answer in this link
I have two mongoid models:
bid.rb and supplier.rb
class Bid
include Mongoid::Document
field :amount, type: BigDecimal
embeds_one :supplier
end
I would like to query the embedded :supplier :name and display the :bid :amount in a JSON response.
I have tried this all kinds of ways, the furthest I got was:
Bid.all.pluck(:supplier, :amount) which only returns the supplier id and amount.
Right now I can write bid_data = Bid.all to get the following JSON response:
{"bid_data":
[{"_id":{"$oid":"58a0a9a531d77f01529a22ba"},
"amount":"5335.0",
"supplier":{"_id":{"$oid":"58a087b131d77f01529a229c"},"name":"Ford","comment":3}
}]}
How can I query the Bid.supplier.name in a controller?
Ideally I would like something like Bid.all.pluck(:supplier.name, :amount)
When you say:
embeds_one :supplier
you're really saying that the bids collection has a Hash field called supplier and that Hash should be wrapped up in the usual Mongoid::Document stuff. That means that you can query supplier like any other Hash:
Bid.where('supplier.name' => 'Ford')
I'm having some problems trying to understand how Mongoid does its sorting. I have 2 models, Gig and Venue, both of which are associated by a belong_to has_many relationship.
I'm trying to sort objects from Gig by the attribute 'name' of the Venue Object to no avail.
I'm hoping someone out there would be able to point me to the right direction.
Below are a truncated model description.
My Query is also below:
# Gig Model
class Gig
include Mongoid::Document
include Mongoid::Paperclip
include SearchMagic
belongs_to :owner, :class_name => "User", :inverse_of => :owns
belongs_to :venue
has_and_belongs_to_many :attenders, :class_name => "User", :inverse_of => :attending
has_and_belongs_to_many :artistes
<snip>
end
# Venue Model
class Venue
include Mongoid::Document
include Mongoid::Paperclip
include SearchMagic
has_many :gigs
field :foursquare_id, type: String
embeds_one :address
embeds_many :user_ratings
field :facebook, type: String
field :twitter, type: String
field :website, type: String
field :name, type: String
field :postal, type: String
field :tel, type: String
field :venue_type, type: String
field :description, type: String
field :rating, type: Float, default: 0.0
<snip>
end
# Console
>> Gig.desc('venue.name').map{|f| f.venue.name}
=> ["*SCAPE", "Velvet Underground", "Blujaz Lounge", "Velvet Underground", "Home Club", "Wh
ite House, Emily Hill", "Zouk", "Zouk", "The Pigeonhole", "Home Club", "Home Club", "Home C
lub"]
# sorting doesn't work
You can't join in mongo. If you need joins, use a relational database. A "feature" of non-relational databases is that you can't do joins.
You have basically two choices:
a before_save callback, which will inject the name of the venue into the gig as an additional field (see for instance https://github.com/rewritten/timebank/blob/master/lib/mongoid/denormalize.rb)
a map-reduce task, which after any modification of any venue or gig, will update the venue name into the gig as an additional field.
In the end, you need a field in the Gig collection to order it.
Currently, I can add the creator_id like this in my controller:
#entry = Entry.new(params[:entry].merge(:creator => current_user._id))
If this is my model:
class Entry
include Mongoid::Document
belongs_to :User
field :creator, :type => String
field :title, :type => String
field :content, :type => String
field :scorea, :type => Integer
field :scoreb, :type => Integer
field :scorec, :type => Integer
end
Is there a better way to do this?
Your model doesn't looks very good, do you really want to store the user_id in a string field?
I suggest you change your models to following:
class Entry
include Mongoid::Document
belongs_to :creator, :class_name => 'User', :inverse_of => :entries
# field definitions
end
class User
include Mongoid::Document
has_many :entries, :inverse_of => :creator
end
Once you change the models you can continue using what you are now or alternatively:
#entry = current_user.entries.build(params[:entry])
Update:
The method to initialize entry is not much different in the way I did it. It is just more towards the rails way of doing things. The main difference is that you were not using the associations. From your model definitions it is clear that you want a one-to-many association between user and entries and this is how you create such associations. Associations has a lot of goodies attached to them, like you can do following things:
user.entries << entry # add a entry to users, will automatically change entry.creator_id
entry.creator = user # sets creato_id = user_id
entry.creator # returns associated user. no need to do User.find(entry.creator_id)
user.entries # returns all entries for use <=> Entry.where(creator_id: user.id)
for more details go to http://mongoid.org/docs/relations.html
There are no better way to do. Or you can do it in 2 line :
#entry = Entry.new(params[:entry])
#entry.creator = current_user._id
this second case allow you to add creator field in attr_protected
You can do it in this manner
#entery = Entery.new(params[:entry])
#entery.creator = current_user
or
#entery.creator_id = current_user.id
hence you can assigned id of creator to this entery.
If I have a model called Product
class Product
include Mongoid::Document
field :product_id
field :brand
field :name
...
belongs_to :store
And then I have a model called Store
class Store
include Mongoid::Document
field :name
field :store_id
...
has_many :products
def featured_products
Products.where(:feature.exists => true).and(store_id: self[:store_id]).asc(:feature).asc(:name)
end
How do I create an accessible #store.featured_products which is the results of this query? Right now I get an error that reads
uninitialized constant Store::Products
Use Product, not Products.
I just stumbled on this looking for something else and although the above answer is correct, and the question is ages old, it is very inefficient for what is being asked. As I stumbled on it, so might others.
The example usage above wished to scope the products relationship to just featured products, so a model such as this would work faster (assumed Mongoid 3.0+):
class Product
include Mongoid::Document
field :product_id
field :brand
field :name
field :feature
...
belongs_to :store
scope :featured, where(:feature.exists => true).asc(:feature).asc(:name)
end
class Store
include Mongoid::Document
field :name
field :store_id
...
has_many :products
end
Then instead of #store.featured_products, you could call #store.products.featured. Now if you assume Mongoid 2.x was used, as this was 2011, and looking at this then Mongoid 1.x maybe not have had scopes, the same thing could be achieved like this:
class Product
include Mongoid::Document
field :product_id
field :brand
field :name
field :feature
...
belongs_to :store
end
class Store
include Mongoid::Document
field :name
field :store_id
...
has_many :products
def featured_products
self.products.where(:feature.exists => true).asc(:feature).asc(:name)
end
end
Now the reason both of these are more efficient that just a boolean search on the Products collection is that they start with a cursor creation across the _id field. This is indexed and limits the subsequent where query to just the related documents. The difference would be noticeable on most collection sizes, however the bigger the collection grew the more time would be wasted on a boolean of the entire collection.