0

First, reference links to other questions I read through. They might be clues to what I am experiencing, although I am not understanding enough yet to see the solution to my problem.

How can I use Python to transform MongoDB's bsondump into JSON?

Unable to deserialize PyMongo ObjectId from JSON

I've got a Flask Restful API I'm working on. An excerpt of my code is as follows:

class DeviceAPI(Resource):

    def get(self, deviceID):
        # do the query
        deviceCollection = db['device']
        device = deviceCollection.find_one({'deviceID': deviceID})

        print device   #1
        print ''

        print json_util.dumps(device)   #2
        print ''

        s = json_util.dumps(device)
        print s  #3
        print ''

        results = {}
        results['device'] = s 

        print results  #4

        # respond
        return results #5

At Print #1, I get the following, and I understand and expect this.

{u'deviceID': u'ABC123', u'_id': ObjectId('....')}

At Print #2 and #3 are identical outputs as expected, and again I understand and expect this (I think).

{"deviceID": "ABC123", "_id": {"$oid": "...."}}

Print #4 has an added key in the dictionary. However, it looks like the value of the key:value is a string where it should be the dictionary as in #2 and #3.

{'device': '{"deviceID": "ABC123", "_id": {"$oid": "...."}}'}

The returned result, #5, according to CURL is along the lines of the following. There are the added / in the there. I suspect because of #4 value looking like a string and that continues in #5 as well.

{"device": "{\"deviceID\": \"ABC123\", \"_id\": {\"$oid\": \"....\"}}"}

I'm trying to get a pure JSON output, not a string representation of the device document. #2 and #3 looked like JSON, but in #4 became a string. Why? And how to do this correctly?

3 Answers 3

1

I believe it's because json_utils.dumps is converting your device variable into a string when you should be just returning a complete json object. You essentially end up returning something that resembles this:

return {"device": "a string that resembles json"}

Instead, modify your code to look like this:

class DeviceAPI(Resource):
    def get(self, deviceID):
        # do the query
        deviceCollection = db['device']
        device = deviceCollection.find_one({'deviceID': deviceID})

        results = {'device': device}
        return results

Now, we're returning json that looks more like this:

return {"device": {"deviceID": "ABC123", "_id": {"$oid": "...."}}}

However, it looks like the recommended way to return json in flask is to actually use the flask.jsonify method so that Flask will return a proper response object:

from flask import jsonify

class DeviceAPI(Resource):
    def get(self, deviceID):
        # do the query
        deviceCollection = db['device']
        device = deviceCollection.find_one({'deviceID': deviceID})

        return jsonify(device=device)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for looking at this Michael0x2a. I agree with the concise analysis on what is being returned, but the proposed solutions aren't working, there is a "TypeError: ObjectId('....') is not JSON serializable" error.
The reason for the dumps from the BSON json util is so that internal objects such as ObjectId and Date BSON types are serialized to a standard JSON form. It's very mongoDB specific and not just a base python case. Hence the problem with using other json encoders.
1

Michael0x2a helped to clear some fog in my mind, and after more experimenting and thinking this through, the following is working for me.

results['device'] = json.loads(json_util.dumps(device))

In my experimenting I was using json_util.dumps and json_util.loads. But I didn't recognize that while json_util.dumps was converting the BSON like item to JSON string, that json_util.loads was converting it directly back. Therefore, another function was needed to take the string like JSON output of json_util.dumps and make it into a dictionary JSON like object. Thus a combo was needed. This is using "import json" and "from bson import json_util" (of Pymongo).

Comments

0

Thank you for your reply I had the same problem as you, and it was fixed just because you post back the solution, thanks million! Follow below my code

from flask_restplus import Namespace, Resource, fields
from .. import mongo

import json
from bson import json_util

api = Namespace('inventory', description='Store management related operations')

@api.route('/items')
class Inventory(Resource):
    def get(self):
        inventory_collection = mongo.db.inventory
        resp = inventory_collection.find({})
        a = json.loads(json_util.dumps(resp))
        return {'result': a }


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.