HasManyThrough vs HasAndBelongsToMany - loopbackjs

What is the diff between these HasManyThrough vs HasAndBelongsToMany ??
https://docs.strongloop.com/display/public/LB/HasManyThrough+relations
VS
https://docs.strongloop.com/display/public/LB/HasAndBelongsToMany+relations

The answer lies in the relation name itself. I'm going to use examples provided in the documentation.
HasManyThrough:
physician hasMany patients through appointment
patient hasMany physician through appointment
Here, both physicians and patients are related to each other through appointments but are not directly related. appointment model is helping to create a relation as it belongs to both physician and patient. Because of appointment, a patient can book an appointment to as many physicians. And a physician can see as many patients who booked him/her.
HasAndBelongsToMany:
student has many classes and belongs to many classes.
classes has many students and belongs to many student.
Here, both students and classes are related to each other directly. students generally attend many classes like physics, chemistry etc - so they have many classes. And since attendance is taken in each class, therefore students belong to many classes.
Likewise, a class is attended by many students - so class have many students. And since attendance is maintained for each student, therefore class belong to many students.
Note:
if two classes are related with many-to-many relationship through an intervening model like appointment, then use hasManyThrough.
if two classes are directly related with many-to-many relationship, use hasAndBelongsToMany

hasManyThrough is just a hasMany relation for which a through model has been defined. See params.through in https://github.com/strongloop/loopback-datasource-juggler/blob/4c9e91423f3d356bb544790075dcb7f891450096/lib/relation-definition.js#L659.
hasAndBelongsToMany is essentially a shortcut to set a hasManyThrough relation on both sides. If a through model has not been defined it just concatenates both model names and tries to find a model by that name, if that fails it just tries to fetch relations from a table by that name (https://github.com/strongloop/loopback-datasource-juggler/blob/4c9e91423f3d356bb544790075dcb7f891450096/lib/relation-definition.js#L1630).
If you define a hasAndBelongsToMany relation between Assembly and Part, it will set a hasMany and belongsTo relations between Assembly and AssemblyPart and also another pair of them between Part and AssemblyPart. If AssemblyPart model is not defined, it will just try to use a table (or collection I guess if MongoDB, I'm mostly a RDBMS guy) named assemblypart. It will also define a hasManyThrough relation from Assembly to Part using AssemblyPart as the through Model (so that assembly.parts is available) and its counterpart from Part to Assembly (part.assemblies).
What I'm trying to say is that you can achieve exactly the same as hasAndBelongsToMany by manually defining an AssemblyPart model with the corresponding hasMany and belongsTo to both Assembly and Part models and the two hasManyThrough: from Assembly to Part and from Part to Assembly.

Related

Why Many to Many relationship with self can't be symmetrical

I'm trying to make a model with many to many relationship to itself and this relationship will also have a specific table that will store some information about the relationship, but I'm running into some problems.
I tried to make a many to many relationship with diferent models like the Django docs say, and it's worked fine in some other point of my application. But now I tried to do something like this:
Let's say that I want a model that represents an object (called Item) that is made by other items and also is used to make some other items. For instance, an object Door is made by wood and lock, but Door will also be used to make a House. I thought in something like this for my models
class Item(models.Model):
name = models.CharField(max_length=100)
items = models.ManyToManyField("self",through='IsMadeBy')
class IsMadeBy(models.Model):
itemResult = models.ForeignKey('Item', related_name='itemResult')
itemPart = models.ForeignKey('Item', related_name='itemPart')
amountUsed = models.PositiveIntegerField()
I'm getting the error message:
Many-to-many fields with intermediate tables must not be symmetrical.
So, adding the argument
symmetrical=False
to my relationship the error stops.
With that being said, I want to know how this really works under the hood. For intance, what the symmetrical means in this context in a database level? I would appreciate if anyone could give examples maybe using SQL statements, since right now my brain can't see the overall situation and really learn this concept of symmetrical relationship in a many to many relationship with self.
Look at the Django docs:
https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ManyToManyField.symmetrical
With symmetric relationship if i'm your friend then you my friend too - in Django terms, you have one relation.
With non-symmetric direct and reverse relations can be different, you have related_set. For example, if i'm you manager, you not my manager at the same time, but manager via employee_set can have many employees.

Can I make a dynamc number of foreign keys to a single (self) django model?

I'm currently creating an equipment management database and need to allow equipment to be associated with other equipment.
Thanks to this stackoverflow question I currently have something akin to the following (vastly simplified):
class Equipment(models.Model):
equipment_title = models.CharField()
relates_to = models.ForeignKey('self')
However, to relate a dynamic number of equipment to other equipment I think I need something like a one-to-many field that doesn't exist natively within Django, e.g. a filter housing may be associated with many filter units, and several filter housings may be associated with a machine tool.
How can I get around this? I'm not sure that it's the right place for a many-to-many field...
A ForeignKey is a one-to-many relationship, defined on the "many" side. Since your relationship is pointing to self anyway, it already does what you want.

Association attributes in a Django one-to-many foreignkey relationship

I would like to model a relationship between a Story class and a Series class.
(I.e. a trilogy of novels)
The relationship is a "one to many" (a series can contain many Stories but a Story can only be part of one Series).
Model-wise this could simply be solved by a foreign key on Story,
part_of = models.ForeignKey(Series
, on_delete=models.CASCADE
, related_name='contains_story')
But I would like a sequence number as an attribute of this relationship.
i.e. (1:The long Earth, 2:The long war, 3:The long Mars, ...).
I could make it an attribute of Story but that's not clean, a Story not part of a Series should not have a sequence number.
In a "many-to-many" this can be solved using the "through" option.
by specifying a class and adding attributes to that class.
part_of = models.ManyToManyField(Series, through='SeriesPart')
But "part of a series" is not a "many-to-many" relationship and I want to avoid modelling it like this and having to restrict it in code, so how should I solve this best?
I'm not sure your objection makes much sense. The reason why you might store an extra attribute on the through table of a many-to-many relationship is precisely because each side of the relationship can have multiple items, and the attribute value is only relevant to one specific combination. (In the case of the example in the Django docs, John was in the Quarrymen before he was in the Beatles, so there are separate joined_date values for John<->Quarrymen, John<->Beatles, and Paul<->Beatles.)
In your case, a story can only be part of one series. There is no other position for The Long Earth other than as part 1 of the Pratchett/Baxter series; it can't simultaneously be part 1 of that but also part 2 of something else. So there's no reason not to store the series number on the story model itself. Stories that are not part of a series can simply leave that blank, just like they leave the FK to Series blank.

Many-to-Many relationship with check on Membership

I wish to create with a database with following models and constraints.
1) Student with attributes name, roll number
2) Exam with attributes exam_code, exam_subject
3) Option with attributes option_name, and ManyToManyField on Exam
4) Application with user, exam, ManyToManyField on Options(new)
Basically there will be many exams and options. Student is entitled to choose a subset of options pertaining to his examination choice.
edit: With the new model Application, I suppose the problem boils down to using javascript in the interface for limiting the options available in the interface.
The next challenge lies in handling students with multiple subjects and their subset of options should be a intersection of options(as two different exams might have options in common) available for both exams. Any guidance on this part would be great.
As it stands right now, the Student doesn't really play into the equation. All that matters is what options are available for the particular exam in question (where Student is only nominally related in that the particular exam is a data point on it).
So, that being the case, the available options to a student is always a function of:
some_student.exam_taken.available_options.all()
What you may be wanting, is the ability for a student to have taken multiple exams, and then have all of the available options for all of the exams taken -- a sort of aggregate.
If that's the case, first, you would require a M2M relationship established between Student and Exam (instead of the Foreign Key). Then, you could get all available options from all exams via:
Option.objects.filter(exam__student=some_student).distinct()

Multi-Table Inheritance in Django. I'm not sure I understand

Im not sure I understand the advantage/purpose of multi-table inheritance… but it may be what I'm looking for. Im dealing with Restaurants. My current logic is that I have a Company model which is likely (but not always) a Restaurant. Sometimes a Company can be a "parent" company, in-which case the Company model has a one-to-many with a Branch model. Both the Company and Branch models would have common fields, such as street address, contact info. If the Company has only one "branch" I can assume it's the Restaurant itself and so I don't need to attach a Branch object to the Company. Does this make sense? I know im repeating myself with with the street address [...] but it seems like an elegant way to store the data if I were to read the db directly.
Im not sure if multi-table inheritance is what I need. I just can't wrap my head around it by only looking at https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance.
edit: also open to taking any suggestions on a better db layout if im doing it wrong.
Model inheritance is useful in general because you do queries like Company.objects.all() to return all companies (including restaurants) and also Restaurant.objects.all() to return only restaurant companies. Just like 'regular' inheritance, it might be helpful to include common fields in a parent (Company) model on all the children models (Restaurant). For example, all Companies might have an address field, but only Restaurants might have a food_type field.
I've documented links to a few snippets that implement a "subclassing queryset" which basically lets you do a query like Company.objects.all() and have it return to you results like [<Company> < Restaurant>, <Company>, <Company>, < Restaurant> ]. Check out the link:
http://jazstudios.blogspot.com/2009/10/django-model-inheritance-with.html
The downside of this multi-table approach is that it introduces an extra join in your query between the Company parent table and the child Restaurant table.
An alternatieve would be to create an abstract model. This creates a separate table for Company and for Restaurant with redundant fileds. With multi-table inheritance, if we wanted to look up the address field on a Restaurant instance, we would be referencing (behind the scenes) the related Company model. With abstract inheritance, there would actually be an address field on the Restaurant table. Also, using the abstract inheritance, I don't think you can do Company.objects.all() and expect that it will return instances that were added as Restaurants, nor can you use the subclassing querysets from the snippits linked above.
Hope this helps,
Joe