Skip to content

Commit 51441fe

Browse files
committed
DOCSP-46701: Serialization (#168)
(cherry picked from commit 8079aa9)
1 parent 925da8f commit 51441fe

File tree

3 files changed

+109
-143
lines changed

3 files changed

+109
-143
lines changed

source/index.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ MongoDB {+driver-short+} Documentation
2424
Data Formats </data-formats>
2525
Logging </logging>
2626
Monitoring </monitoring>
27+
Serialization </serialization>
2728
Third-Party Tools </tools>
2829
FAQ </faq>
2930
Troubleshooting </troubleshooting>
@@ -100,6 +101,22 @@ Specialized Data Formats
100101
Learn how to work with specialized data formats and custom types in the
101102
:ref:`pymongo-data-formats` section.
102103

104+
Logging
105+
-------
106+
107+
Learn how to configure logging in the :ref:`pymongo-logging` section.
108+
109+
Monitoring
110+
----------
111+
112+
Learn how to monitor changes to your application in the :ref:`pymongo-monitoring` section.
113+
114+
Serialization
115+
-------------
116+
117+
Learn how {+driver-short+} serializes and deserializes data in the
118+
:ref:`pymongo-serialization` section.
119+
103120
Third-Party Tools
104121
-----------------
105122

source/serialization.txt

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
.. _pymongo-serialization:
2+
3+
=============
4+
Serialization
5+
=============
6+
7+
.. facet::
8+
:name: genre
9+
:values: reference
10+
11+
.. meta::
12+
:keywords: class, map, deserialize
13+
14+
.. contents:: On this page
15+
:local:
16+
:backlinks: none
17+
:depth: 2
18+
:class: singlecol
19+
20+
Overview
21+
--------
22+
23+
In this guide, you can learn how to use {+driver-short+} to perform
24+
serialization.
25+
26+
Serialization is the process of mapping a {+language+} object to a BSON
27+
document for storage in MongoDB. {+driver-short+} automatically converts basic {+language+}
28+
types into BSON when you insert a document into a collection. Similarly, when you retrieve a
29+
document from a collection, {+driver-short+} automatically converts the returned BSON
30+
back into the corresponding {+language+} types.
31+
32+
You can use {+driver-short+} to serialize and deserialize the following {+language+}
33+
types:
34+
35+
- ``str``
36+
- ``int``
37+
- ``float``
38+
- ``bool``
39+
- ``datetime.datetime``
40+
- ``list``
41+
- ``dict``
42+
- ``None``
43+
44+
For a complete list of {+language+}-to-BSON mappings, see the `bson <{+api-root+}bson/index.html>`__
45+
API documentation.
46+
47+
Custom Classes
48+
--------------
49+
50+
To serialize and deserialize custom {+language+} classes, you must implement custom logic
51+
to handle the conversion. The following sections show how to serialize and deserialize
52+
custom classes.
53+
54+
Serializing Custom Classes
55+
~~~~~~~~~~~~~~~~~~~~~~~~~~
56+
57+
To serialize a custom class, you must convert the class to a dictionary. The following
58+
example serializes a custom class by using the ``vars()`` method, and then inserts the
59+
serialized object into a collection:
60+
61+
.. code-block:: python
62+
63+
class Restaurant:
64+
def __init__(self, name, cuisine):
65+
self.name = name
66+
self.cuisine = cuisine
67+
68+
restaurant = Guitar("Example Cafe", "Coffee")
69+
restaurant_dict = vars(restaurant)
70+
71+
collection.insert_one(restaurant_dict)
72+
73+
To learn more about inserting documents into a collection, see the :ref:`pymongo-write-insert`
74+
guide.
75+
76+
Deserializing Custom Classes
77+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78+
79+
To deserialize a custom class, you must convert the dictionary back into an instance of
80+
the class. The following example retrieves a document from a collection, and then converts
81+
it back into a ``Restaurant`` object from the preceding example:
82+
83+
.. code-block:: python
84+
85+
def deserialize_restaurant(doc):
86+
return Restaurant(name=doc["name"], cuisine=doc["cuisine"])
87+
88+
restaurant_doc = collection.find_one({"name": "Example Cafe"})
89+
restaurant = deserialize_restaurant(restaurant_doc)
90+
91+
To learn more about retrieving documents from a collection, see the :ref:`pymongo-retrieve`
92+
guide.

source/troubleshooting.txt

Lines changed: 0 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -110,149 +110,6 @@ frameworks.
110110
if __name__ == "__main__":
111111
app.run()
112112

113-
Query Works in the Shell But Not in {+driver-short+}
114-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115-
116-
After the ``_id`` field, which is always first, the key-value pairs in a BSON document can
117-
be in any order. The ``mongo`` shell preserves key order when reading and writing
118-
data, as shown by the fields "b" and "a" in the following code example:
119-
120-
.. code-block:: javascript
121-
122-
// mongo shell
123-
db.collection.insertOne( { "_id" : 1, "subdocument" : { "b" : 1, "a" : 1 } } )
124-
// Returns: WriteResult({ "nInserted" : 1 })
125-
126-
db.collection.findOne()
127-
// Returns: { "_id" : 1, "subdocument" : { "b" : 1, "a" : 1 } }
128-
129-
{+driver-short+} represents BSON documents as Python dictionaries by default,
130-
and the order of keys in dictionaries is not defined. In Python, a dictionary declared with
131-
the "a" key first is the same as one with the "b" key first. In the following example,
132-
the keys are displayed in the same order regardless of their order in the ``print``
133-
statement:
134-
135-
.. code-block:: python
136-
137-
print({'a': 1.0, 'b': 1.0})
138-
# Returns: {'a': 1.0, 'b': 1.0}
139-
140-
print({'b': 1.0, 'a': 1.0})
141-
# Returns: {'a': 1.0, 'b': 1.0}
142-
143-
Similarly, Python dictionaries might not show keys in the order they are
144-
stored in BSON. The following example shows the result of printing the document
145-
inserted in a preceding example:
146-
147-
.. code-block:: python
148-
149-
print(collection.find_one())
150-
# Returns: {'_id': 1.0, 'subdocument': {'a': 1.0, 'b': 1.0}}
151-
152-
To preserve the order of keys when reading BSON, use the ``SON`` class,
153-
which is a dictionary that remembers its key order.
154-
155-
The following code example shows how to create a collection
156-
configured to use the ``SON`` class:
157-
158-
.. code-block:: python
159-
160-
from bson import CodecOptions, SON
161-
162-
opts = CodecOptions(document_class=SON)
163-
164-
CodecOptions(document_class=...SON..., tz_aware=False, uuid_representation=UuidRepresentation.UNSPECIFIED, unicode_decode_error_handler='strict', tzinfo=None, type_registry=TypeRegistry(type_codecs=[], fallback_encoder=None), datetime_conversion=DatetimeConversion.DATETIME)
165-
collection_son = collection.with_options(codec_options=opts)
166-
167-
When you find the preceding subdocument, the driver represents query results with
168-
``SON`` objects and preserves key order:
169-
170-
.. io-code-block::
171-
172-
.. input::
173-
:language: python
174-
175-
print(collection_son.find_one())
176-
177-
.. output::
178-
179-
SON([('_id', 1.0), ('subdocument', SON([('b', 1.0), ('a', 1.0)]))])
180-
181-
The subdocument's actual storage layout is now visible: "b" is before "a".
182-
183-
Because a Python dictionary's key order is not defined, you cannot predict how it will be
184-
serialized to BSON. However, MongoDB considers subdocuments equal only if their
185-
keys have the same order. If you use a Python dictionary to query on a subdocument, it may
186-
not match:
187-
188-
.. io-code-block::
189-
190-
.. input::
191-
:language: python
192-
193-
collection.find_one({'subdocument': {'b': 1.0, 'a': 1.0}}) is None
194-
195-
.. output::
196-
197-
True
198-
199-
Because Python considers the two dictionaries the same, swapping the key order in your query
200-
makes no difference:
201-
202-
.. io-code-block::
203-
204-
.. input::
205-
:language: python
206-
207-
collection.find_one({'subdocument': {'b': 1.0, 'a': 1.0}}) is None
208-
209-
.. output::
210-
211-
True
212-
213-
You can solve this in two ways. First, you can match the subdocument field-by-field:
214-
215-
.. io-code-block::
216-
217-
.. input::
218-
:language: python
219-
220-
collection.find_one({'subdocument.a': 1.0,
221-
'subdocument.b': 1.0})
222-
223-
.. output::
224-
225-
{'_id': 1.0, 'subdocument': {'a': 1.0, 'b': 1.0}}
226-
227-
The query matches any subdocument with an "a" of 1.0 and a "b" of 1.0,
228-
regardless of the order in which you specify them in Python, or the order in which they're
229-
stored in BSON. This query also now matches subdocuments with additional
230-
keys besides "a" and "b", whereas the previous query required an exact match.
231-
232-
The second solution is to use a ``~bson.son.SON`` object to specify the key order:
233-
234-
.. io-code-block::
235-
236-
.. input::
237-
:language: python
238-
239-
query = {'subdocument': SON([('b', 1.0), ('a', 1.0)])}
240-
collection.find_one(query)
241-
242-
.. output::
243-
244-
{'_id': 1.0, 'subdocument': {'a': 1.0, 'b': 1.0}}
245-
246-
The driver preserves the key order you use when you create a ``~bson.son.SON``
247-
when serializing it to BSON and using it as a query. Thus, you can create a
248-
subdocument that exactly matches the subdocument in the collection.
249-
250-
.. note::
251-
252-
For more information about subdocument matching, see the
253-
`Query on Embedded/Nested Documents <https://www.mongodb.com/docs/manual/tutorial/query-embedded-documents/>`__
254-
guide in the {+mdb-server+} documentation.
255-
256113
Cursors
257114
-------
258115

0 commit comments

Comments
 (0)