Skip to content

Insertion failure when replacing unknown field with dbref value #1255

@smeng9

Description

@smeng9

Background

When javascript processes JSON or when MongoDB handles DBRef they keep the key value pairs ordered.
As we can see from the MongoDB source code, the expected format for DBRef should always have $ref in the first place, $id in the middle place, and $db in the last place as {$ref:, $id:, $db:}
https://github.com/mongodb/mongo/blob/b21647a5e19e5980186e57f77be0b1e0ef92a087/src/mongo/db/update/storage_validation.cpp#L86

Expected Behavior

Tell us what should happen.

Below are the steps to reproduce the issue

  1. define a works'' resource with allow_unknown'' set to True, and ``schema'' set to {}
  2. create an item with {"title": "my work", "owner": {"$ref": "people", "$id": "objectid_in_people"}}
    curl 'http://127.0.0.1:5000/works/ -X POST-H 'content-type: application/json' -d '{"title": "my work", "owner": {"$ref": "people", "$id": "objectid_in_people"}}'
  3. get the created item using curl http://127.0.0.1:5000/works/objectid_in_work and we will get
    {"title": "my work", "owner": {"$id": "objectid_in_people", "$ref": "people"}}
  4. Try to PUT the data from step 3 to the same item endpoint

We noticed the order of $id and $ref are swapped in the GET response.
If we swap the order of $id and $ref in owner field again to {"$ref": "people", "$id": "objectid_in_people"}, then we are able to successfully replace the document.

When we are returning a dictionary for the DBRef, we are not using the OrderedDict, and we lose the order.

if isinstance(obj, DBRef):

Actual Behavior

Tell us what happens instead.

Traceback (most recent call last): 
File "/usr/local/lib/python3.7/site-packages/eve/io/mongo/mongo.py", line 509, in change_request
    coll.replace_one(filter, changes) if replace else coll.update_one( 
File "/usr/local/lib/python3.7/site-packages/pymongo/collection.py", line 925, in replace_one collation=collation, session=session), 
File "/usr/local/lib/python3.7/site-packages/pymongo/collection.py", line 851, in _update_retryable _update, session) 
File "/usr/local/lib/python3.7/site-packages/pymongo/mongo_client.py", line 1248, in _retryable_write return self._retry_with_session(retryable, func, s, None) 
File "/usr/local/lib/python3.7/site-packages/pymongo/mongo_client.py", line 1201, in _retry_with_session return func(session, sock_info, retryable) 
File "/usr/local/lib/python3.7/site-packages/pymongo/collection.py", line 847, in _update retryable_write=retryable_write) 
File "/usr/local/lib/python3.7/site-packages/pymongo/collection.py", line 818, in _update _check_write_command_response(result) 
File "/usr/local/lib/python3.7/site-packages/pymongo/helpers.py", line 217, in _check_write_command_response _raise_last_write_error(write_errors) 
File "/usr/local/lib/python3.7/site-packages/pymongo/helpers.py", line 199, in _raise_last_write_error raise WriteError(error.get("errmsg"), error.get("code"), error) 
pymongo.errors.WriteError: Found $id field without a $ref before it, which is invalid.

Environment

  • Python version: 3.7.3
  • Eve version: 0.8.1

Suggested Fix

We can switch to OrderedDict to preserve the order. When user post DBRef data structures in JSON, they should also be aware of the order of the key value pairs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions