【问题标题】:Pymongo BSON Binary save and retrieve?Pymongo BSON 二进制保存和检索?
【发布时间】:2014-03-31 10:13:00
【问题描述】:

我正在使用 Python 和 MongoDB 尝试紧密保存浮点数组。

我可以正确创建和存储*

我无法检索可用格式的数据。

>>> import random, array, pymongo
>>> from bson.binary import Binary as BsonBinary
>>> con = pymongo.Connection('localhost', 27017)
>>> mm = con['testDatabase']
>>> vals = [random.random() *100 for x in range(1, 5)]
>>> vals
[2.9962593, 64.5582810776, 32.3781311717, 82.0606953423]
>>> varray = array.array('f', vals)
>>> varray
array('f', [2.9962593, 64.5582810776, 32.3781311717, 82.0606953423])
>>> vstring = varray.tostring()
>>> vstring
'\xb7\xc2?@\xd7\x1d\x81B5\x83\x01B\x13\x1f\xa4B'
>>> vbson = BsonBinary(vstring, 5)
>>> vbson
Binary('\xb7\xc2?@\xd7\x1d\x81B5\x83\x01B\x13\x1f\xa4B', 5)
>>> doc1 = { 'something': 1 , 'else' : vbson}
>>> doc1
{'something': 1, 'else': Binary('\xb7\xc2?@\xd7\x1d\x81B5\x83\x01B\x13\x1f\xa4B', 5)}
>>> mm.test1.insert(doc1)
ObjectID('530f7af1d809d80d3db1f635')
>>> gotdoc = mm.test1.find_one()
>>> gotdoc
{u'_id': ObjectId('530f7af1d809d80d3db1f635'), u'something': 3, u'else': Binary('\xb7\xc2?@\xd7\x1d\x81B5\x83\x01B\x13\x1f\xa4B', 5)}
>>> gotfield = gotdoc['else']
>>> gotfield
Binary('\xb7\xc2?@\xd7\x1d\x81B5\x83\x01B\x13\x1f\xa4B', 5)
>>> from bson import BSON
>>> BSON.decode(gotfield)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method decode() must be called with BSON instance as first argument (got Binary instance instead)
>>> gotfield.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xb7 in position 0: ordinal not in range(128)
>>>

一旦我得到我的 Python 字符串,我就可以得到我的随机浮点数组。但是怎么做呢?

【问题讨论】:

    标签: python mongodb pymongo bson


    【解决方案1】:

    让我们来看看错误:

    1. 出现第一个错误只是因为您需要一个实际的 BSON 对象。请注意,您从未编码过任何数据——创建bson.binary.Binary 对象并不意味着调用BSON.encode()

    2. 这就是 PyMongo 欺骗你的地方。 bson.binary.Binary 是运行时修补的 strbytes 实例 (see source)。这就是你得到第二个错误的原因:你调用的实际上是str.decode(),而不是BSON.decode()。因此,gotfield 包含您最初存储的随机浮点数据,但对象本身绑定了一些不同的方法(例如repr())。

    【讨论】:

    • 这是有道理的,但解决方法是什么?你如何从 bson.binary.Binary 回到原来的 dtype ?可以使用 cPickle 或类似的东西来完成吗?
    【解决方案2】:

    我来了~我只是想办法。希望这对您有所帮助。

    from cStringIO import StringIO
    from PIL import Image
    

    保存图片:

    content = StringIO(f.read())
    
    c = dict(
        content=bson.binary.Binary(content.getvalue()),
    )
    # insert dict into my database, sha1 is primary key
    image_data[sha1] = c
    

    检索图像:

    f = image_data[sha1]
    image = Image.open(StringIO(f['content']))
    

    ----编辑----

    如果你想从网络服务器返回一张图片。这样做:

    f = image_data[sha1]
    # f['mime'] is the type of image, for example 'png'.
    resp = Response(f['content'], mimetype='image/' + f['mime'])
    return resp
    

    【讨论】:

      【解决方案3】:

      在最后的解码阶段使用array.fromstring。我可以像这样到达您所在的同一地点:

      >>> from bson import Binary
      >>> import array
      >>> gotstring = Binary('\xb7\xc2?@\xd7\x1d\x81B5\x83\x01B\x13\x1f\xa4B', 5)
      

      最后:

      >>> a = array.array('f')
      >>> a.fromstring(gotstring)
      >>> a
      array('f', [2.9962594509124756, 64.55828094482422, 32.37813186645508, 82.0606918334961])
      

      【讨论】:

        【解决方案4】:

        您需要在存储之前对数组进行编码,并且不应使用array.tostring。请查看文档here

        from bson import BSON
        bson_string = BSON.encode({"hello": "world"})
        >>> bson_string
        '\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00'
        >>> bson_string.decode()
        {u'hello': u'world'}
        

        【讨论】:

        • 我不需要数据结构的 bson 编码。我有一个有效编码和存储的二进制对象。我需要将其转换回我输入的内容。所以,显然,BSON.encode/decode 不是正确的方法。
        【解决方案5】:

        BSON.decode(得到域)

        它有一个TypeError问题,你应该像下面这样写

        BSON.decode(bson.BSON(gotfield))

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-24
          • 2014-10-13
          • 2014-07-02
          • 1970-01-01
          • 2018-02-16
          • 2015-08-02
          • 1970-01-01
          • 2017-06-08
          相关资源
          最近更新 更多