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?

Community
  • 1
  • 1
TimothySwieter
  • 397
  • 1
  • 2
  • 7

3 Answers3

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)
Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
  • 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. – TimothySwieter Apr 19 '14 at 02:43
  • 1
    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. – Neil Lunn Apr 19 '14 at 03:44
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).

TimothySwieter
  • 397
  • 1
  • 2
  • 7
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 }