I am trying to use hasMany relationship in loopback. I have problem while using it. I have an array, which is contains to ids from target model and I want to find all elements belongs to that array and I want to list them. How can I do it?
#property({
type: 'array',
itemType: 'string',
})
exampleArray?: string[];
#hasMany(() => MainComponent, {keyFrom: 'exampleArray', keyTo: 'id'})
mainComponent: MainComponent[];
Hello from the LoopBack team đź‘‹
I have an array, which is contains to ids from target model
LoopBack's hasMany relation uses a foreign key on the target model instance to establish the relation. For example, if a Category has many Product models, then Product model must have a property linking it back to the owning category - this is typically categoryId.
IIUC your domain model, you want the source model (Category) to store the list of target model ids (Product.id) that belong to this category. In LoopBack, we call such relation type referencesMany.
LoopBack 4 does not implement referencesMany relation yet, please join the discussion in GitHub issue loopback-next#2488 or at least upvote đź‘Ť the issue to let us know about your interest.
Related
I'm trying to use DynamoDB for my JAVA project and I have this (from my point of view) strange scenario that I have to cover. Let me to explain how I organize my table:
Suppose that I have to store these info related to Books:
book_id (UUID) used as PK autogerated
author_id (UUID)
type (String)
book_code (UUID) this different as concept from book_id
publishing_house_id (String)
book_gender (String)
And additional dynamic attributes that are not queryable and I'm thinking to store as Document (JSON)
Now, the queries that I need are:
Insert/Get/Update/Delete book by book_id
Get all book by author_id
Get all book by author_id and type
Get book by book_code, publishing_house_id, book_gender (I would like to highlight that this tuple will be unique)
Using the book_id as PK I'll be able to cover the first query set (CRUD using the book id)
For the query #2 and #3 the idea is to create a GS index where the author_id is the PK and type is the SK.
In order to cover the query #4 I'm thinking to:
Create an dedicated Attribute book_sk where I'll store:
book_gender#publishing_house_id#book_code
Create a Local Secondary Index using this book_sk as SK
Probably I can move book_code, publishing_house_id, book_gender into a Document field instead to have these unquerable attributes here.
I'm not very sure about this design.
What do you think?
In that case, is it better to use a LSI or GSI for the query #4?
For #4, if you're always getting a book by those three together, then make an attribute with that concatenated value and use it as the PK of a GSI, making it easy to directly look up.
I have and Event and EventCategory model with a many-to-many relationship.
There are 2 event categories - past (ID of 2) and future (ID of 1).
I want to find all Events in the future via
models = Event.objects.filter(categories__slug='future')
And then update them so they are all in the past.
Should I create a list of the Event instances, then delete from the related table, and insert the instances with the new category ID - just wanted some guidance if possible, on the most efficient way to do this.
Many thanks
I am not sure if this is the most efficient solution for my needs but it works:
Find the new category I want to associate to the events (this is the "past" category)
cat = EventCategory.objects.get(pk=2)
Here are my existing relationships, where 1 is the ID of the future category
models = Event.objects.filter(categories__id=1)
for model in models:
model.categories.clear()
model.categories.add(cat)
Now all of the entires in the related table are in the past category.
For example:
class Contact(models.Model):
contacts = models.ManyToManyField('self', through='ContactRelationship', symmetrical=False)
What does the symmetrical=False parameter do?
When should it be left as True, and when should it be set as False?
How does this settings affect the database (does it create extra columns etc)?
Let's say you have two instances of Contact, John and Judy. You may decide to make John a contact of Judy. Should this action also make Judy a contact of John? If so, symmetrical=True. If not, symmetrical=False
Here is what is says in the documentation:
Only used in the definition of ManyToManyFields on self. Consider the following model:
from django.db import models
class Person(models.Model):
friends = models.ManyToManyField("self")
When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, it doesn’t add a person_set attribute to the Person class. Instead, the ManyToManyField is assumed to be symmetrical – that is, if I am your friend, then you are my friend.
By default, the value of symmetrical is True for Many to Many Field which is a bi-directional relationship.
Using a through table (symmetrical=False):
But you can also imagine a situation where you don't need this type of relationship so you can add symmetrical=False. And, this can be achieved by using a through table because by default symmetrical is False if you use a through table:
Recursive relationships using an intermediary model are always defined as non-symmetrical – that is, with symmetrical=False – therefore, there is the concept of a “source” and a “target”. In that case 'field1' will be treated as the “source” of the relationship and 'field2' as the “target”.
So you can imagine a situation where you do need the direction i.e. let's say there is a Node model and it has a relationship with itself using a through table. If we didn't have the requirement of direction here we could go with the example shown earlier. But now we also need a direction from one node to another where one being source and another one being target and due to nature of this relationship it cannot be symmetrical.
Lets say I have three related models - Container, Category and Item. Each model has two string properties - a name and an uuid (as well as the normal "id" field.) The uuid fields will be used as SlugRelatedFields to express relationships in the REST interface. A Container contains a set of items and a set of categories; each item is related to a category.
I'd like to create an entire container (with all its items and categories) in one POST. But I can't seem to create a serializer that allows that. When I try to do so, I get an error when the serializer tries to decode an item - it finds that the referenced category doesn't exist yet. Which is not surprising, since the same POST is going to create it.
In JSON form, here's what I'd like to POST:
{
"name": "My Container",
"uuid": "<container-uuid>",
"categories": [
{
"name": "Category One",
"uuid": "<category-one-uuid>",
}
],
"items": [
{
"name": "Item One",
"uuid": "<item-one-uuid>",
"category": "<category-one-uuid>",
},
{
"name": "Item Two",
"uuid": "<item-two-uuid>",
"category": "<category-one-uuid>",
}
]
}
So that example would create one container, one category and two items - both items would be related to the same category.
I can use a SlugRelatedField in the Item serializer to identify the associated Category by uuid. But in this scenario, that throws an error:
Object with uuid=<category-one-uuid> does not exist.
while deserializing "Item One". Understandably, since that category is not yet in the database.
Is there some way to make this work? Can I override some method in the ItemSerializer to make it look for the associated Category in the Container that is being deserialized, rather than looking at the Categories that already exist in the database? I'm thinking that a solution may require a couple of things:
Ensuring that the categories are de-serialized before the items. What determines that? The order of the "fields" attribute in the serializer?
Using the deserialized categories a create a queryset that is used during deserialization of the items, replacing the database query that is normally used.
Any ideas?
Update 2014-08-22:
I haven't fixed this problem, but I've worked around it. The workaround is a filthy hack, involving a number of parts:
In the model, I changed the definition of the foreignkey reference
from item to category to allow NULL.
In the serializer for Item, I
declared the category as a simple CharField(), rather than a
SlugRelatedField that identifies the Category by its UUID.
In that serializer's "restore_object" method, I grab the specified UUID out of the category field (in the "attrs" dictionary passed to that method). I remove the entry from that dictionary and add an entry to a dictionary that maps Item UUIDs to the associated Category UUIDs. That dictionary is held in a per-request cache, as described here: Per-request cache in Django?
Then I have a handler for the "pre_save" signal on item, and it looks up the required category UUID in that dictionary (using the Items's UUID as key), does a query on the Category table to find the right item and uses that to set the foreignkey field.
So, when a request comes in to create a new Container with associated Items and Categories:
Because the Category UUID reference in the Item is just a CharField, it is NOT verified against a query of the existing categories in the database. So the serializer proceeds to saving stuff in the database.
The Categories are saved to the DB as normal. (They get saved first, presumably just because of the order of the Seriliazer's "fields" array.)
When the "restore_object" method is used to construct the Item that will be saved, the UUID of the required Category is stashed away for later use, and that "CharField" value is discarded from the fields used to construct the Item.
When the Item is about to be saved, the signal handler retrieves the stashed UUID and uses it to fetch the correct (newly-created) category to fill out the foreignkey field.
Hacky as heck, right? But it seems to work. I'd love to rework this one day to use a more elegant solution but in the real world, that won't happen.
Here is my idea:
go to rest_framework/serializers.py
look for the save_object method from the ModelSerializer class
there, you should find a piece of code like this one:
if getattr(obj, '_nested_forward_relations', None):
# Nested relationships need to be saved before we can save the
# parent instance.
for field_name, sub_object in obj._nested_forward_relations.items():
if sub_object:
self.save_object(sub_object)
setattr(obj, field_name, sub_object)
My best guess is that here the serializer tries to save your nested objects (categories and items).
put a breakpoint there and try to figure out how exactly those objects are created (in what order)
if you find anything interesting, you can update your post, and I'll try and help you further.
Good luck!
I have a Product entity and a Shop entity.
A shop can have 0 to n products and a product can be in only one shop.
The product entity table is thus refering to the Shop entity through a shop_id table field.
When querying for the products of a given shop using doctrine query builder, we can do this:
$products = $this->getDoctrine()->getRepository('MyBundle:Product')
->createQueryBuilder('p')
->where('p.shop = :shop')
->setParameter('shop', $shop) // here we pass a shop object
->getQuery()->getResult();
or this:
$products = $this->getDoctrine()->getRepository('MyBundle:Product')
->createQueryBuilder('p')
->where('p.shop = :shopId')
->setParameter('shopId', $shopId) // we pass directly the shop id
->getQuery()->getResult();
And the both seem to work... I'm thus wondering: can we always pass directly entity ids instead of entity instances in such cases (ie: on a doctrine entity field that refers to another entity)?
I initially thought that only the first example would work...
According to the Doctrine documentation, you can pass the object to setParameter() if the object is managed.
extract from the documentation:
Calling setParameter() automatically infers which type you are setting as value. This works for integers, arrays of strings/integers, DateTime instances and for managed entities.
for more information, please see:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#binding-parameters-to-your-query
I might be wrong, but I think that if you pass object instance instead of id number, Doctrine will automatically call $instance->getId() making your two queries the same when translated into SQL (even DQL).