I am having some trouble with setting up a hasOne relation, which probably comes from me understanding the relation wrongly?
I have 2 Models, one user model, and one location model. What I want to add now is a relation between user and location, meaning a user has a current location. But if I set up a hasOne relation on the user model with the location, I end up with a userId property in the location. But this is completely wrong, since several users can have the same current location, so the user model should store the location id, not the location the user id. So how can I achieve what I want, so that I can afterwards query the user and include the current location?
I can of course add a property to the user and store the id of the location there, but then I can't as easily include the location in a user request. So I would prefer using relations to achieve this.
Your problem is a bit unclear, given the comments of Brian's post, but if you absolutely need Users to share a given set of locations then you would be better off using User belongsTo location.
This will create a locationId field in User, and you will be able to GET api\Users\{userId}\location
Eventually, you can set a location hasMany User to retrieve from a given location all the users in there
The relation name is referring to the relational meaning of "has one," which means that for each user, there exists one (and only one) entry in the location table. Each user "has one" entry in the location table, and if your data needs to show that two users have the same location, it just means the location table would store identical location data with different userIds. This is still perfectly fine for relational mapping, and allows you to do User.location calls.
What you are looking for is slightly different, which would be "Location hasMany Users," because you will be sharing location entries with multiple users. Read this as "for each location entry, many users could share it." You'll have to query a bit differently and use the include: ['location'] filter when you want to return the User with location data included (otherwise you'll only get the locationId value).
Relation builder:
$ slc loopback:relation
? Select the model to create the relationship from: Location
? Relation type: has many
? Choose a model to create a relationship with: user
? Enter the property name for the relation: users
? Optionally enter a custom foreign key:
? Require a through model? No
location.json:
{
"name": "Location",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"lat": {
"type": "number"
},
"long": {
"type": "number"
}
},
"validations": [],
"relations": {
"users": {
"type": "hasMany",
"model": "user",
"foreignKey": "locationId"
}
},
"acls": [],
"methods": {}
}
Related
So I am using Loopback 3 atm, and I am currently updating the properties of my model. Problem is that the structure will be different as before as certain properties are now split into 2 separate properties, thus if I would place it online that data might be lost due to those changes. (I am using mongodb)
Example original structure:
{
"properties": {
"address": {
"type": "string"
}
}
}
Example new structure:
{
"properties": {
"address": {
"type": {
"street": {
"type": "string"
},
"city": {
"type": "string"
},
"zipcode": {
"type": "string"
}
}
}
}
}
In my case there are also properties that change names instead of address its addressline or something like that.
I know that some of you might say that its better to move address to a separate model but this is just an example in my case im unable to move it to a separate table due to certain circumstances.
So my question is how can you update a model and remap the existing data to follow the new structure to ensure that the original data isn't lost.
Thanks in advance!
Here's my answer
I understand that loopback is database independent and my approach is going against that, nevertheless here's my approach.
We can write migration script based on the underlying db, this is what I tried for postgresdb
#1 For the scenario where data type is being changed.
ALTER TABLE dbname ADD COLUMN address2 jsonb;
UPDATE dbname set address2= to_json(address) ;
ALTER TABLE dbname DROP COLUMN address;
ALTER TABLE dbname RENAME COLUMN address2 TO address;
#2 and for the scenario where name needs to be changed
ALTER TABLE dbname ADD COLUMN addressline jsonb;
UPDATE dbname set addressline= address;
ALTER TABLE dbname DROP COLUMN address;
Hoping to find more and better answer for this question!!
I have a many to many relationship between a Contact and a ContactGroup. One contact can belong to many groups, one group can contain multiple contacts.
I want to be able to display data like this, so I don't need to do multiple queries when showing names of groups where an user belongs.
GET
{
"id": 1,
"name": "Gandalf",
"groups": [
{
"id": 3,
"name": "Lord of the rings"
}
]
}
But if I update, I want to be able to update using ids or urls e.g.
POST
{
"id": 1,
"name": "Gandalf",
"groups": [
[2]
]
}
That would remove it from group 3 and put it to group 2 instead. I know I should write a Writable nested serializer, but I have two questions:
1) I want to do this properly, what is supposed to be a good practice when I want to do this. Shall I send ids or the whole objects like
POST
{
"id": 1,
"name": "Gandalf",
"groups": [
{
"id": 2,
"name": "Wizards"
}
]
}
This one seems a bit weird to me as I need to send information that is not needed (name in this case).
2) If I can go with id/url principle, how shall I do this? In a custom create/update method, I can't have id validated, because a serializer points to a GroupSerializer and doesn't accept int type, it expects GroupSerializer, so accessing validated_data.get('groups') wouldn't get me ids, it would tell me [{"non_field_errors":["Invalid data. Expected a dictionary, but got int."]}]}
I can write 2 serializers - one for create/update and one from displaying data. Do you think it's a correct way of doing this? Am I doing a right think in a first place? What do you think of this approach?
For #1, you can leave the name as read only field in which case you'll have it for read and it'll be discarded for write operations.
For #2 as you want to remain consistent, your best take it to send:
POST
{
"id": 1,
"name": "Gandalf",
"groups": [
{"id": 2}
]
}
You really don't want to have a different style for read and write operations, really.
I was trying to make hasMany relation of model with the same model itself like my model was ticket and in that relations defined are parentTickets and childTickets which are array of tickets and i made a mapping table 'ticketRelation' which is mapping table for the has many relationship.My models are following-
ticket model-
"relations":{
"parentTickets":{
"type":"hasMany",
"model":"ticket",
"foreignKey":"childId",
"through":"ticketRelation"
},
"childTickets":{
"type":"hasMany",
"model":"ticket",
"foreignKey":"parentId",
"through":"ticketRelation"
}
}
ticketRelation-
"relations":{
"pticket": {
"type": "belongsTo",
"model": "ticket",
"foreignKey": "parentId"
},
"ticket": {
"type": "belongsTo",
"model": "ticket",
"foreignKey": "childId"
}
}
My sample data is-
ticket id =1 has child tickets with id =2,3
so when i try to find parentTickets in ticket model by the following URL
http//localhost:3000/api/tickets?filter[include]=childTickets
it give me correct result ie ticket-id =1,childTickets=2,3
but whenever i try to find parentTickets for ticket by the following URL, it is not giving me correct result
http//localhost:3000/api/tickets?filter[include]=parentTickets
The data retrieved is-
ticket-id=1, parentTicket -1
so the problem i noticed is might be that loopback is expecting the relation name to be same as that of model name which we are specifying in the relation in the mapping table( ticketRelation) to retrieve the data.
I want to see which users can see a particular album. I use the following query to get my albums and their privacy settings:
SELECT id,allow,deny,description,friends,value FROM privacy WHERE id IN
(SELECT object_id FROM album WHERE owner=me())
and it returns something like this for each album:
{
"id": 212102865605678,
"allow": "211824028961234,212367312342178",
"deny": null,
"description": "John Doe, Work People",
"friends": "SOME_FRIENDS",
"value": "CUSTOM"
}
The second ID in the allow column is right. That's the ID for the 'Work People' friendlist.
But the other ID isn't really the ID of 'John Doe'.
If I use the FB.api from javascript using 'me/friends' I get this:
{
"name": "John Doe",
"id": "100005318169867"
}
Same name, but different ID. I'm quite certain that they're the same user (I don't have many friends). Is this the difference between some internal database ID and external ID?
Any help would be greatly appreciated!
Recently me/feed started to include entries sent by current user to groups.
The id field is invalid for those entries and simply returns "false".
Changing the first part of the id to the one mentioned in "to" gives a valid entry.
It could be a good workaround except there is no way to immediately know which posts are normal and which posts are to Groups.
I did notice that on posts to groups there is an extra field 'version' that is not documented. Anyone knows what this field means?
Example entry:
...
"id": "1188060277_343671429042688",
"from": {
"name": "My Name",
"id": "1188060277"
},
"to": {
"data": [
{
"version": 1,
"name": "Group Name",
"id": "194744830602016"
}
]
},
...
Hope this helps :)
groups
The Groups that the user belongs to.
user_groups or friends_groups.
An array of objects containing the version(old-0 or new Group-1), name, id, administrator (if user is the administrator of the Group) and bookmark_order(at what place in the list of group bookmarks on the homepage, the group shows up for the user).
http://developers.facebook.com/docs/reference/api/user/