I am trying to store messages and I want to store to and from User reference as below:
class Message
include Mongoid::Document
include Mongoid::Timestamps
field :from, type: Moped::BSON::ObjectId
field :to, type: Moped::BSON::ObjectId
end
class User
include Mongoid::Document
field :username, type: String
end
Is the above the correct way of doing so? I can imagine one way is to create User as a custom type, but that seems a lengthy direction to take. Ideally I want to be able to reference the User directly as so: message.from.username or message.from['username'] and be able to validate the presence of the from and to fields.
Any help would be much appreciated.
class Message
belongs_to :from, class_name: 'User', inverse_of: nil
belongs_to :to, class_name: 'User', inverse_of: nil
...
Message.where(from: my_user)
Related
Foo, Bar and Baz are all Mongoid collection models. There are the only collections in the DB.
Is there a more efficient way to get all the data in the DB?
Foo.all + Bar.all + Baz.all
I don't know a way of querying several collections at the time, and I believe that if one try to do that will defeat the purpose of using a NONSQL DB like MongoDB.
However, there is one way of archiving this behaviour in MongoDB. Using embedded documents. For example:
class Everything
include Mongoid::Document
include Mongoid::Timestamps
embeds_many :foos, class_name: 'Foo', inverse_of: :everything
embeds_many :bars, class_name: 'Bar', inverse_of: :everything
embeds_many :bazs, class_name: 'Bazs', inverse_of: :everything
end
class Foo
include Mongoid::Document
field :foo, type: String
embedded_in :everything, class_name: 'Everything', inverse_of: :foos
end
class Bar
include Mongoid::Document
field :bar, type: String
embedded_in :everything, class_name: 'Everything', inverse_of: :bars
end
class Bazs
include Mongoid::Document
field :baz, type: String
embedded_in :everything, class_name: 'Everything', inverse_of: :bazs
end
Doing Everything.all will retrieve all documents in Everything along with all the embedded documents in one call.
In my code I have a user class:
class User
include Mongoid::Document
has_and_belongs_to_many :person_record_bookmarks, inverse_of: nil, :class_name => "PersonRecord"
end
now it will generate person_record_bookmarks_ids in my document. This name is too long, is there any way to store it as shorter name in the database? In embed documents we can use store_as:, but seems it doesn't work for references.
foreign_key is what you are looking for
class User
include Mongoid::Document
has_and_belongs_to_many :person_record_bookmarks, inverse_of: nil, :class_name => "PersonRecord", foreign_key :shorter_name
end
then your user will be:
{...shorter_name:[ObjectId("..."),ObjectId("...")]...}
You can user user.shorter_name to retrieve the list of ids or user.person_record_bookmarks to retrieve all PersonRecordBookmarks.where({_id: {$in: shorter_name})
I have this releationship
class Cupboard
include Mongoid::Document
field :name, type: String
has_many :ingredients
end
class Recipe
include Mongoid::Document
field :name, type: String
has_many :ingredients
end
class Ingredient
include Mongoid::Document
field :name, type: String
field :description, type: String
belongs_to :cupboard
belongs_to :recipe
end
I need to create a method in Cupboard model to find a recipe that contains the same ingredients as the cupboard, I don't find in the Mongoid docs a method to find it.
I need something like Recipe.find( #all cupboard.ingredients.ids )
thanks in advance
def shared_recipes
ingredients.map(&:recipe).uniq
end
I'm still getting my head around MongoDB and Mongoid in particlar.
Let's say I have a User and each User has one Thingamajig. When I create the User
I want the system to autmatically also create a blank Thingamajig for that User.
Each Thingamajig has a whatsit field that must be unique if it has a value, but is allowed to have no value when created.
So I define the following classes.
class Thingamajig
include Mongoid::Document
field :whatsit, type: String
index({whatsit: 1}, {unique: true, name: 'whatsit_index'})
end
class User
include Mongoid::Document
field :name, type: String
index({name: 1}, {unique: true, name: 'user_name_index'})
embeds_one :thingamajig, dependent: :nullify, autobuild: true
end
However what I find when I
User.create!(name: 'some name')
is that User.find(name: 'some name').thingamajig is nil.
Questions:
How can I ensure that each User gets an associated Thingamajig? and
How do I specify that the name field of a User is required?
FYI I am using Sintara not Rails (if that matters to anyone).
1 - The autobuild: true option normally should have done the trick. I think the problem is that you forgot to add the other side of the relation to the Thingamajig model:
class Thingamajig
include Mongoid::Document
embedded_in :user
...
end
2 - To specify required fields, use validations:
class User
include Mongoid::Document
field :name, type: String
validates_presence_of :name
...
end
Mongoid uses ActiveModel validations.
I have the following models
class Track
include Mongoid::Document
field :artist, type: String
field :title, type: String
has_many :subtitles, as: :subtitleset
end
class Subtitle
include Mongoid::Document
field :lines, type: Array
belongs_to :subtitleset, polymorphic: true
end
class User
include Mongoid::Document
field :name, type: String
has_many :subtitles, as: :subtitleset
end
And in my ruby code when I create a new Subtitle I'm pushing it in the appropriate Track and User like this:
Track.find(track_id).subtitles.push(subtitle)
User.find(user_id).subtitles.push(subtitle)
The problem is that it gets pushed only in the User and not in the Track also. But if I remove the second line it gets pushed it the Track. So why isn't working for both?
I get this in the Subtitle document:
"subtitleset_id" : ObjectId( "4e161ba589322812da000002" ),
"subtitleset_type" : "User"
If a subtitle belongs to something, it has an ID pointing to that something. A subtitle cannot belong to two somethings at once. If the belonging is polymorphic, a subtitle can belong to something whose class is not specified - but it still cannot belong to two somethings at once.
You want:
class Track
include Mongoid::Document
field :artist, type: String
field :title, type: String
has_many :subtitles
end
class Subtitle
include Mongoid::Document
field :lines, type: Array
belongs_to :track
belongs_to :user
end
class User
include Mongoid::Document
field :name, type: String
has_many :subtitles
end
And then you will be able to:
Track.find(track_id).subtitles.push(subtitle)
User.find(user_id).subtitles.push(subtitle)