How to add to a list type in Python Eve without replacing old values
Asked Answered
A

3

9

I have a very similar setup to the person in this question: How do I update a list data_relation in Python Eve with a users resource and a friends sub-resource of list type.

users = {
    …
    ‘friends’: {
    'type': 'list’, 
        'schema': {
        'type': 'objectid’, 
        'data_relation': { 
            'resource': 'users’ 
        } 
    }
 }
},

However, when I try to add a new value to the friends list, the other values in the list get replaced by the new value. How do I add a single value to the list and keep the old values?

GET /users/5522987f893e3902048c55ff

{
"_updated": "Wed, 15 Apr 2015 17:22:07 GMT",
"_created": "Mon, 06 Apr 2015 14:30:23 GMT",
"_id": "5522987f893e3902048c55ff",
"friends": [
    "552e9eb0893e391063045edc"
]
}

PATCH /users/5522987f893e3902048c55ff
{"friends": [“550f288d893e390204b0a5ac”]}

RESPONSE:
{
"_updated": "Wed, 15 Apr 2015 19:38:06 GMT",
"_created": "Mon, 06 Apr 2015 14:30:23 GMT",
"_status": "OK",
"_id": "5522987f893e3902048c55ff"
}

GET /users/5522987f893e3902048c55ff

{
"_updated": "Wed, 15 Apr 2015 19:38:06 GMT",
"_created": "Mon, 06 Apr 2015 14:30:23 GMT",
"_id": "5522987f893e3902048c55ff",
"friends": [
    "550f288d893e390204b0a5ac"
]
}

I have also tried PUT, but it replaces the list with the new value as well.

EDIT: I just tried using POST.

POST /users/5522987f893e3902048c55ff/friends
{"552e9eb0893e391063045edc"}

RESPONSE:
{
"_status": "ERR",
"_error": {
    "message": "The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again.",
    "code": 404
}
}

AND

POST /users/5522987f893e3902048c55ff
{"friends": ["552e9eb0893e391063045edc"]}

RESPONSE:
{
"_status": "ERR",
"_error": {
    "message": "The method is not allowed for the requested URL.",
    "code": 405
}
}
Amplification answered 15/4, 2015 at 20:10 Comment(5)
You should use a POST to add a new element ...Tambratamburlaine
Never use MS Word to edit you programs or data. You have some ellipses and quotes that are autocorrected.Iamb
Thanks for the quick response! I just edited my question after I tried posting a new friend.Amplification
@AmyEubanks I have the same problem. How did you resolve this since it's not natively supported in eve.Paginate
@Paginate I just posted my workaround.Amplification
W
1

POST will allow you to add a new document to the users endpoint. If it is returning a 405 then you most likely need to enable the POST method by adding it to the RESOURCE_METHODS list, as all endpoints are read-only by default; see docs (alternatively you can only enable POST for the individual endpoint by adding the method to the local resource_methods instead.)

PATCH allows for the replacing of individual fields (as opposed to PUT, which will replace the whole document). So with PATCH you can atomically update the friends list by replacing it with a new value (a new list ObjectIds in your case), but you cannot push a single new ObjectId inside the existing list, I am afraid.

Wimple answered 16/4, 2015 at 6:25 Comment(5)
I am able to POST to 'users', just not to a single 'users/<id>'. I see that it is not allowed, because I get a ConfigException from Eve when I add it to the 'ITEM_METHODS' list. I'll use PATCH like you say and keep track of old values. Thanks for your answer!Amplification
Is there any plan to support the push-to-list-field operation in Eve?Saguenay
@nicola, is there a way to append on the list documents.Diatessaron
Haven't yet figured a way to allow it in a proper RESTful way, to be honest.Wimple
So does that mean if i want to add objectIds into a list, inside a resource, the only way is keep resending PATCHs as the list keeps growing? I.e., in my client i have to cache each instance?Venola
A
2

Here is the workaround that I used. It's probably not the most efficient way to do this, but it worked for me.

Instead of having a users/friends list like I had originally planned, I ended up creating a resource for shares. In my case, I wanted to know which crystals were shared with which users. So when I query crystals/<crystal_id>/shares, I should get a list of the shares for that crystal.

I think you could apply a solution like this to the users/friends scenario if you swap crystals for users and shares for friends. You might put two different user_id data_relations in your friends_schema (my shares_schema).

shares_schema = {
    'crystal_id': {
        'type': 'objectid',
        'required': True,
        'data_relation': {
            'resource': 'crystals',
            'embeddable': True,
        },
    },
    'user_id': {
        'type': 'objectid',
        'required': True,
        'data_relation': {
            'resource': 'users',
            'embeddable': True,
        },
    },
}

shares = {
    'internal_resource': True,
    'schema': shares_schema,
}

crystals_shares = {
    'schema': shares_schema,
    'url': 'crystals/<regex("[a-f0-9]{24}"):crystal_id>/shares',
    'datasource': {'source': 'shares'},
}
Amplification answered 12/2, 2016 at 3:22 Comment(0)
W
1

POST will allow you to add a new document to the users endpoint. If it is returning a 405 then you most likely need to enable the POST method by adding it to the RESOURCE_METHODS list, as all endpoints are read-only by default; see docs (alternatively you can only enable POST for the individual endpoint by adding the method to the local resource_methods instead.)

PATCH allows for the replacing of individual fields (as opposed to PUT, which will replace the whole document). So with PATCH you can atomically update the friends list by replacing it with a new value (a new list ObjectIds in your case), but you cannot push a single new ObjectId inside the existing list, I am afraid.

Wimple answered 16/4, 2015 at 6:25 Comment(5)
I am able to POST to 'users', just not to a single 'users/<id>'. I see that it is not allowed, because I get a ConfigException from Eve when I add it to the 'ITEM_METHODS' list. I'll use PATCH like you say and keep track of old values. Thanks for your answer!Amplification
Is there any plan to support the push-to-list-field operation in Eve?Saguenay
@nicola, is there a way to append on the list documents.Diatessaron
Haven't yet figured a way to allow it in a proper RESTful way, to be honest.Wimple
So does that mean if i want to add objectIds into a list, inside a resource, the only way is keep resending PATCHs as the list keeps growing? I.e., in my client i have to cache each instance?Venola
B
0

I reply with my solution, I hope it will be useful after so long... You don't really need a specific implementation in eve to update lists, it can be easily solved using hooks: In resource where the relation points, define a Database event hook on_update (prior to insert):

app.on_update_users += update_users

Define the function as follows:

def update_users(updates, original):
    if 'friends' in original:
        if 'friends' in updates:
            updates['friends'] = list(set(updates['friends'] + original['friends']))
    return True

patching:

curl -X PATCH -H 'Content-Type: application/json' -i 'http://127.0.0.1/users/63a12c8795e8ef7a4617823e' --data '{"friends":["63a12c8795e8ef7a4617823f"]}'

After the patch you will have the new element in the friends list and the previous ones will not have been deleted (if they exist).

Bombardier answered 22/12, 2022 at 5:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.