many to many relationships with mongoid - mongodb

I'm wondering on how to do a many to many relationship with mongoid. Here is a visual representation of the models, with the small ones being join tables:
!http://i.imgur.com/lJxoRSb.jpg
I have set up my model like this (as an example) using RoR:
class Event
include Mongoid::Document
field :name, type: String
field :place, type: String
field :when, type: String
field :price, type: Integer
field :participants, type: Integer
field :short_description, type: String
has_many :users
#has_many :users, :through => :user_events
end
what would i need to join the event model with user model with interest model (if this is even possible)? I know mongoid isn't the best option for this but i'm stuck with using it.
Thanks in advance!

Try the following:
embeds_many :user_events
See also http://mongoid.org/en/mongoid/v3/relations.html#embeds_many
Do not use join tables in MongoDB, use arrays of embedded objects/references instead. MongoDB has array values, take advantage of them!
With a many-to-many relationship, you have a choice on placing the references on the first collection, or the second collection, or on both. If you put references in both collections, you have to do your own updates for consistency as needed by your application.

Related

Association to different entities for a multi-purpose entity in MongoDB?

This question relates to MongoDB with mongoid. My use case is as follows:
I have an Address entity that can be used in many different contexts, e.g. it could be the address of a customer, vendor, user, etc. In addition to that, a customer, for example, can have multiple addresses, such as an office address, a delivery address, and more.
Here is the Address entity, for example:
class Address
include Mongoid::Document
field :suburb, type: String
field :city, type: String
field :postcode, type: String
field :country, type: String
end
From the customer side, my thinking is that I would have the following:
class Customer
include Mongoid::Document
has_many :customer_addresses
end
class CustomerAddress
include Mongoid::Document
field :address_type, type: String
has_one :address
belongs_to :customer
end
According to the mongoid documentation, I need to put a belongs_to macro into Address to point back to the CustomerAddress entity for it to work properly.
However, Address, in this case, is multi-purpose. It could also be a vendor address, user address, or belong to any other entity that needs an address.
Perhaps I am thinking too much in terms of relational databases? What is the MongoDB approach for solving this problem?
Secondly, if I didn't want a CustomerAddress entity, but wanted different fields on Customer, such as :office_address and :delivery_address, each resolving to an Address, how would I do that?
See https://docs.mongodb.com/mongoid/master/tutorials/mongoid-relations/#polymorphism for handling multiple classes using an address.
CustomerAddress as a separate collection is likely not the best choice for MongoDB, look into embedding.
Use class_name option when the name of the association differs from the name of the class implementing it, which you'd need to have multiple associations of the same class.

Unsure how to model many-to-many relationship in MongoDB

I'm new to MongoDB and I'm trying to model a Many to Many relationship into at least 2 collections (I need two collections for the project). What I'm having is a collection of universities, faculties and specializations, and another collection for students and their gradebook (this was the middle entity between specializations and students in SQL, not sure if it's needed in Mongo anymore). I tried to use This as an inspiration but it limits me as I can only search students by university id (I want for example to search students from a certain specialization or a certain faculty). I could put every row from university, faculty and specialization in the student collection and vice versa but I really don't think it's ideal. Here's what I have so far:
db.students.insertOne({_id:1, firstname: 'John', lastname: 'Silas', ethnicity:'english', civilstatus:'single', residence:'London', email:'johnSilas#gmail.com', gradebook:[{ year:2018, registrationyear:2017, formofeducation:'traditional'}], universities:[1]})
db.universities.insertOne({_id:1, name:'University of London', city:'London', adress:'whatever', phone: 'whatever', email: 'whatever#gmail.com', faculty:[{name: 'Law', adress:'whatever', phone: 'whatever', email: 'whatever#gmail.com'}], specialization:[{name:'criminal rights', yearlytax:5000, duration: 3, level:'bachelordegree', language:'english'}], students: [1,2]})
I'm sorry if I don't understand basic noSQL concepts, I am new to it. Thanks in advance.
Basic patterns for many to many association between A and B:
Inline references
On A, store the list of B ids in a field like b_ids
On B, store the list of A ids in a field like a_ids
This requires two writes whenever an association is created or destroyed, but requires either zero or one joins at query time to traverse the association (if you just want the id of Bs for a given A and you have the A already no further queries are needed).
Join model
Create a model C which has two fields: a_id and b_id. Each association is represented by a single instance of C.
This requires one write whenever an association is created or destroyed, but requires joins on all queries involving association (potentially two joins per query).

Understanding Mongoose Schema better

I am relatively new to the MongoDb world, coming from a MS Sql / Entity framework environment.
I am excited about Mongo, because of:
MongoDb's ability to dynamically change the shape of the class/table/collection at run time.
Entity framework does not offer me that.
Why is that so important?
Because I would like to create a generic inventory app and have the product class/collection/table be dynamic for clients to add fields pertinent to their business that cannot be used by everyone, eg. Vin Number, ISBN number, etc.
Now I have come to learn about Mongoose and how it offers a schema, which to me detracts from the flexibility of MongoDb described above.
I have read in a few sections that there is such an animal as mixed-schema, but that appears to be dynamic relative to the data type and not the collection of properties for the given class/collection/table.
So this is my question:
If I am looking at developing a generic class/collection /table that affords clients to shape it to include whatever fields/properties they want that pertain to their business, dynamically, should I abandon the whole notion of mongoose?
I found a benefit today as to where a Schema may be warranted:
Allow me to preface though and say I still thoroughly am excited about the whole idea that Mongo allows a collection to be reshaped at run time in circumstances where I may need ti to be. As mentioned above, a perfect example would be an Inventory app where I would want each client to add respective fields that pertain to their business as opposed to other clients, such as a Car dealership needing a VIN Number field, or a Book store needing a ISBN Number field.
Mongo will allow me to create one generic table and let the client shape it according to his own wishes for his own database at run time - SWEET!
But I discovered today where a schema would be appropo:
If in another table that will not be 're-shapeable', say a user table, I can create a Schema for pre-determined fields and make them required, as such:
var dbUserSchema = mongoose.Schema({
title: {type:String, required:'{PATH} is required!'},
FullName: {
FirstName: {type: String, required: '{PATH} is required!'},
LastName: {type: String, required: '{PATH} is required!'}
}
});
By having the respective first-name and last-name required from the schema, the database will not add any records for a user if they are not both included in the insert.
So, I guess one gets the best of both worlds: Tables that can be re-shaped and thru a schema, tables that can be rigid.

How can I implement a dynamic checklist with additional comments using MongoDB and rails?

I am building a project that involved car servicing. I have an admin panel which allows the creation of services, and each service has a number of checks to perform (The checks themselves and belong to multiple services). The solution looks like this:
class Service
include Mongoid::Document
field :name, type: String
field :price, type: Integer
has_and_belongs_to_many :checks
end
class Check
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :services
end
These checks are performed on an instance 'Appointment'. So when an appointment is carried out, all the necessary checks are displayed (depending on the type of service).
What is the best way to create and store an instance of these checks?
In mySQL, I would create an appointment_check table with appointment_id and check_id as a compound key, and have the details of the check in there.
Is this the best way to resolve this in MongoDB? But surely this involves a join..
Is there a solution I'm missing?
Thanks
MongoDB does not know the concept of joins. So in your case you would not have a appointment_check table, as the has_and_belongs_to_many are just arrays of ids, in both sides.
What I would do in your case, is to have a belongs_to :appointment in the Check model, so you can have a appointment_id and the check_id within the same document.

Combining postgres_ext (or Rails 4) arrays with associations

I'm trying to develop a many-to-many relationship between tags (in the tags table) and items (in the items table) using a field of type integer[] on each item.
I know that Rails 4 (and Rails 3 via postgres_ext) has support for Postgres' arrays feature through the :array => true parameter, but I can't figure out how to combine them with Active Record associations.
Does has_many have an option for this? Is there a gem for this? Should I give up and just create a has_many :through relationship (though with the amount of relations I'm expecting this is probably unmanageable)?
At this point, there isn't a way to use relationships with arrays in Rails. Using the selected answer though, you will run into the N+1 select issue. Say you get your posts and then the tags for it on each post with "tags" method defined in the class. For each post you call the tags on, you will incur another database hit.
Hopefully, this will change in the future and we can get rid of the join table (especially given that Postgres 9.4 will include support for foreign keys in Arrays).
All you really need to do is
def tags
Tag.where(id: tag_ids)
end
def add_tag(tag)
self.tag_ids += [tag.id] unless tag_ids.include?(tag.id)
end
At least that's what I do at the moment. I do some pretty cool stuff with hashes (hstore) as well with permissions. One way of handling tags is to create the has_many through and persist the tags in a string array column as they are added for convenience and performance (not having to query the 2 related tables just to get the names out). I you don't necessarily have to use active record to do cool stuff with the database.