I'm trying to retrieve only books where only authors in favorite_authors are among the authors for the book. (note: not an exact match, but an exclusion of all books with any authors other than those in favorite_authors).
favorite_authors = User.favorite_authors
=> [BSON::ObjectId('5363c73c4d61635257516000'),
BSON::ObjectId('5363c73c4d61635257516001'),
BSON::ObjectId('5363c73c4d61635257516002'),
BSON::ObjectId('5363c73c4d61635257516003'),
BSON::ObjectId('5363c73c4d61635257516004'),
BSON::ObjectId('5363c73c4d61635257516005'),
BSON::ObjectId('5363c73c4d61635257516006')]
class Author
include Mongoid::Document
field :name, type: String
class Book
include Mongoid::Document
field :name, type: String
field :authors, type: Array
Some naive pseudo code to give you an idea of what I'd like to do:
Book.where(authors: relevant_authors).not.where(authors: !relevant_authors)
Ideally, I'd like to accomplish this using a Mongoid Origin query.
Related
I'm trying to figure out how to query related collections in Mongoid.
Here is my object model (simplified for brevity):
Category
-------------------
class Category
include Mongoid::Document
field :name, type: String
...
belongs_to: product
end
class Product
include Mongoid::Document
field :name, type: String
...
has_one :category
end
I'm trying to build a query to get all products with category with a particular name e.g. "Toy"
products = Product.where('category.name' => 'Toy')
I get a nil collection back. I think mongoid does not support this types of queries directly. How do I build a query that will accomplish that?
Try the following
category = Category.find_by(name: 'Toy')
# all the following will work
products = Product.where(category: category)
products = Product.where(category_id: category.id)
this will work, but it's not recommended to use mongoid this way
Mongoid provides relational-style associations as a convenience for application developers who are used to dealing with relational databases, but we do not recommend you use these extensively.
I'm new to MongoDB and Mongoid, using Mongoid 3.1.4 for my Rails (3.2.13) app. I saw in the legacy code people using both type: Moped::BSON::ObjectId and type: String somewhere for the referenced model.
Example
class Team
include Mongoid::Document
field :room_id, type: String
field :leader_id, type: Moped::BSON::ObjectId
...
end
(Using git blame I know these 2 lines written by 2 different people)
I did a search but haven't found the answer for the question when/why to use what type? String or Moped::BSON::ObjectId
Thanks,
Both are a bit odd, you'd usually make relations instead of storing the id directly either as a string or an ObjectId:
class Team
include Mongoid::Document
belongs_to :room
belongs_to :leader
...
end
This will also allow you to read the id directly by calling room_id or leader_id.
For more info check out http://mongoid.org/en/mongoid/docs/relations.html or http://two.mongoid.org/docs/relations.html
If I'd have to choose between the two I'd store the ObjectId instead of the string though, it takes less storage space.
I am using mongoid in Rails 3 and I came across this problem:
Let's say I have a Shape model:
class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
end
And a Canvas model (has many Shapes):
class Canvas
include Mongoid::Document
field :name, type: String
embeds_many :shapes
end
Then a Canvas model "has many Shapes".
I have Browser model inherited from Canvas:
class Browser < Canvas
field :version, type: Integer
end
Then Browswer model should "has many Shapes" now.
But, now I have a "Circle" model inherited from Shape:
class Circle < Shape
field :radius, type: Float
end
And I want to let Browser model to "has many Circles" instead of "has many Shapes". That is to say, I want to overwrite the "has many" relationship in Browser model from "has many Shapes" to "has many Circles".
How should I do it?
I'm not 100% sure, but I think you would just add the line for embeds_many :circles to the Browser model. You wouldn't need to remove the inherited relation.
Since Circle inherits from Shape, circles will get stored in an array stored in the "shapes" key in the Browser document anyway, they'll just have their _type attribute set to "Circle". In other words, having the embeds_many :shapes relation doesn't create anything in the DB that embedding many circles wouldn't create anyway.
It will, however, mean that you have methods such as Browser.frist.shapes available, but you can simply ignore these. Adding the embeds_many :circles will give you the methods for that relation, such as Browser.first.circles.
I have a MongoID User model
class User
include Mongoid::Document
field :name
embeds_many :watchlists
end
which embedded one to many
class Watchlist
include Mongoid::Document
field :description
embedded_in :user
end
I want to search full text into :description field which is in Watchlist child embedded in User. The most heavy search goes through 1.5k descriptions, with a max of 30, 40 words each.
The constrain here, is that I'll deploy on Heroku and they have not free plan for indexing currently.
Then I've tried with mongoid_fulltext (as well as mongoid_search and mongoid-searchable) but without success.
Does anybody have an idea how to do that ?
UPDATE:
This is an example of mongoid_fulltext. The User model embeds many Watchlist(s). I'm searcing a string in :description field, which is in Watchlist child doc :
class Watchlist
include Mongoid::Document
field :description
...
embedded_in :user
end
Watchlist is embedded in User :
class User
include Mongoid::Document
include Mongoid::FullTextSearch
field :name
...
embeds_many :watchlists
def search_in_description
self.watchlists.map{ |w| w.description }.join(' ')
end
fulltext_search_in :search_in_description
end
... but in that way, running User.fulltext_search("a presentation framework based on the power of CSS3") gives me back just the parent doc causing the match (a user instance) and not the watchlists doc ( the child instance ).
See the output: http://pastie.org/3226179
How can I get just the matching "watchlists"? ( I tryed few ways without success )
In MongoDB you cannot query directly for embedded documents. You can query they way you explained in the example to get the parent document, then query on the returned top document user for the desired embedded document among current user watchlists.
If you're going to do that frequently, perhaps you might want to consider using relational has_many rather than embeds_many.
I'm using Ruby on Rails 3.1 with mongoid and trying to set up som rather simple relations between posts, comments, users and tags.
I'm very new to mongodb, and no-sql in general so I'm a bit confused.
What I am trying to accomplish is this:
Users, posts and comments should be able to have multiple tags.
Tags should have name, type and a count of how many times it has been used.
I need to be able to get all available tags so that users kan choose from them.
And the other way around, be able to retrieve tags from users, posts and comments.
I've read a lot about it, and still can't seem to figure out which approach I should take. Should I use referencial or embedded relationships?
I've looked at a couple of gems but no-one seems to work as i described above.
Sidenote: I am going to use Tire for my search-function later on.
Cool, welcome to MongoDB! This is hard to get right and depends on your application but I'll try and give you some pointers based on what you've written and what I think will work best.
This isn't always the case but the general theory is that if an object is always manipulated and viewed in context of another you should embed it inside that object. This is probably the case with comments and posts in your application. Therefore you may want to embed comments inside posts.
However, because you use the tag object in multiple contexts I would make it its own collection like this:
class Tag
include Mongoid::Document
field :tag, type: String
field :type, type: String
field :count, type: Integer
end
Let's run down your requirements and build the models.
Tags should have name, type and a count of how many times it has been used.
Done via above code for Tag class.
Users, posts and comments should be able to have multiple tags.
Ok so let's give each of these classes a "tags" field that has an array of tag IDs, this would be a referential relationship.
class User
include Mongoid::Document
field :first_name, type: String
field :last_name, type: String
field :email, type: String
field :tags, type: Array
end
Also here we will embed comments inside of the posts along with having the array of tag IDs like we do for Users.
class Post
include Mongoid::Document
field :subject, type: String
field :body, type: String
field :tags, type: Array
embeds_many :comments
end
class Comment
include Mongoid::Document
field :name, type: String
field :type, type: String
field :count, type: Integer
embedded_in :post
end
Make sense? There is some more info here on modeling these sorts of relationships in Rails but using mongomapper instead of mongoid (so don't pay attention to the syntax but pay attention to the ideas presented)