python bson.errors.InvalidDocument:无法编码对象:datetime.date(2015, 3, 1)
python bson.errors.InvalidDocument: Cannot encode object: datetime.date(2015, 3, 1)
我有以下功能:
# this is in a module called 'dbw_lib'
def dateTimeOuput(start_days_back, end_days_back):
start_delta = datetime.timedelta(days=start_days_back)
end_delta = datetime.timedelta(days=end_days_back)
start_date = datetime.date.today() - start_delta
end_date = datetime.date.today() - end_delta
return start_date, end_date
def dictByDate(start_days, end_days):
start_date, end_date = dbw_lib.dateTimeOuput(start_days, end_days)
date_string = { "created_at": {"$gte" : start_date, "$lt": end_date } }
user_id_email_dict = dbw_lib.dbwIdToEmailD(user_coll_obj, date_query = date_string) # dict of all user ids and emails
print user_id_email_dict
quit()
当我 运行 key_dicts = dictByDate(90, 60)
时,我得到以下回溯:
Traceback (most recent call last):
File "main.py", line 212, in <module>
program.runProgram()
File "main.py", line 61, in runProgram
report.RcreateReport()
File "filepath/report.py", line 86, in RcreateReport
key_dicts = dictByDate(90, 60)
File "filepath/report.py", line 65, in dictByDate
user_id_email_dict = dbw_lib.dbwIdToEmailD(user_coll_obj, date_query = date_string) # dict of all user ids and emails
File "filepath/dbw_lib.py", line 50, in dbwIdToEmailD
for pair in id_email_cursor:
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/cursor.py", line 968, in __next__
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/cursor.py", line 905, in _refresh
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/cursor.py", line 812, in __send_message
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/mongo_client.py", line 732, in _send_message_with_response
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/mongo_client.py", line 743, in _reset_on_error
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/server.py", line 85, in send_message_with_response
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/message.py", line 107, in get_message
bson.errors.InvalidDocument: Cannot encode object: datetime.date(2015, 3, 1)
datetime.date
不是 bson 编码器的一部分。 (也许作者忘记了它或故意将其遗漏,因为像那样将时间信息附加到日期是模棱两可的。)
但是你可以在 pymongo 中编写一个函数来扩展自定义类型
就像在 json
中扩展 JSONEncoder
一样,您可以在 pymongo 中使用 SONManipulator
:
做类似的事情
import datetime
import pymongo
class MigrationTransformer(pymongo.son_manipulator.SONManipulator):
def _encode_date(self, value):
return datetime.datetime.combine(
value,
datetime.datetime.min.time())
def transform_incoming(self, son, collection):
for (key, value) in son.items():
# datetime.datetime is instance of datetime.date
# compare type explicitly only
if type(value) == datetime.date:
son[key] = self._encode_date(value)
elif isinstance(value, dict): # recurse into sub-docs
son[key] = self.transform_incoming(value, collection)
return son
然后将其附加到您的数据库实例:
db.add_son_manipulator(MigrationTransformer())
(我没有给出 transform_outgoing
方法,因为这与问题无关,但你可以在这里找到它:http://api.mongodb.org/python/current/examples/custom_type.html)
Edit: dict中的key的值是list类型会有问题。出于某种原因,pymongo 没有将它传递给 SONManipulator
。所以列表没有转换。
我已经更新了 class 来处理这个问题(但我没有为 sets
和 tuples
做)。
class MigrationTransformer(SONManipulator):
def _encode_date(self, value):
return datetime.datetime.combine(
value,
datetime.datetime.min.time())
def _handle_list(self, value):
for index, item in enumerate(value):
if isinstance(item, dict):
value[index] = self._handle_dict(item)
elif isinstance(item, list):
value[index] = self._handle_list(item)
elif isinstance(item, datetime.date):
value[index] = self._encode_date(item)
return value
def _handle_dict(self, item):
for (key, value) in item.items():
if type(value) == datetime.date:
item[key] = self._encode_date(value)
elif isinstance(value, dict): # recurse into sub-docs
item[key] = self._handle_dict(value)
elif isinstance(value, list): # recurse into sub-docs
item[key] = self._handle_list(value)
return item
def transform_incoming(self, son, collection):
for (key, value) in son.items():
# datetime.datetime is instance of datetime.date
# compare type explicitly only
if type(value) == datetime.date:
son[key] = self._encode_date(value)
elif isinstance(value, dict): # recurse into sub-docs
son[key] = self.transform_incoming(value, collection)
elif isinstance(value, list): # recurse into sub-docs
son[key] = self._handle_list(value)
return son
只是替换
datetime.date.today()
和
datetime.datetime.today()
但注意前者有日期,后者有 return 日期时间
结果是
PyMongo doesn't support saving date instances. The server doesn't have
a type for dates without times, so there would have to be some
convention used to save dates without times. If you need to save a
date your client should convert it to a datetime instance and you can
save that.
This answer 声明这可以通过 datetime.datetime.combine
方法完成,如下所示:
datetime.datetime.combine(dateWithoutTime, datetime.time.min)
我有以下功能:
# this is in a module called 'dbw_lib'
def dateTimeOuput(start_days_back, end_days_back):
start_delta = datetime.timedelta(days=start_days_back)
end_delta = datetime.timedelta(days=end_days_back)
start_date = datetime.date.today() - start_delta
end_date = datetime.date.today() - end_delta
return start_date, end_date
def dictByDate(start_days, end_days):
start_date, end_date = dbw_lib.dateTimeOuput(start_days, end_days)
date_string = { "created_at": {"$gte" : start_date, "$lt": end_date } }
user_id_email_dict = dbw_lib.dbwIdToEmailD(user_coll_obj, date_query = date_string) # dict of all user ids and emails
print user_id_email_dict
quit()
当我 运行 key_dicts = dictByDate(90, 60)
时,我得到以下回溯:
Traceback (most recent call last):
File "main.py", line 212, in <module>
program.runProgram()
File "main.py", line 61, in runProgram
report.RcreateReport()
File "filepath/report.py", line 86, in RcreateReport
key_dicts = dictByDate(90, 60)
File "filepath/report.py", line 65, in dictByDate
user_id_email_dict = dbw_lib.dbwIdToEmailD(user_coll_obj, date_query = date_string) # dict of all user ids and emails
File "filepath/dbw_lib.py", line 50, in dbwIdToEmailD
for pair in id_email_cursor:
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/cursor.py", line 968, in __next__
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/cursor.py", line 905, in _refresh
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/cursor.py", line 812, in __send_message
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/mongo_client.py", line 732, in _send_message_with_response
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/mongo_client.py", line 743, in _reset_on_error
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/server.py", line 85, in send_message_with_response
File "/Library/Python/2.7/site-packages/pymongo-3.0-py2.7-macosx-10.9-intel.egg/pymongo/message.py", line 107, in get_message
bson.errors.InvalidDocument: Cannot encode object: datetime.date(2015, 3, 1)
datetime.date
不是 bson 编码器的一部分。 (也许作者忘记了它或故意将其遗漏,因为像那样将时间信息附加到日期是模棱两可的。)
但是你可以在 pymongo 中编写一个函数来扩展自定义类型
就像在 json
中扩展 JSONEncoder
一样,您可以在 pymongo 中使用 SONManipulator
:
import datetime
import pymongo
class MigrationTransformer(pymongo.son_manipulator.SONManipulator):
def _encode_date(self, value):
return datetime.datetime.combine(
value,
datetime.datetime.min.time())
def transform_incoming(self, son, collection):
for (key, value) in son.items():
# datetime.datetime is instance of datetime.date
# compare type explicitly only
if type(value) == datetime.date:
son[key] = self._encode_date(value)
elif isinstance(value, dict): # recurse into sub-docs
son[key] = self.transform_incoming(value, collection)
return son
然后将其附加到您的数据库实例:
db.add_son_manipulator(MigrationTransformer())
(我没有给出 transform_outgoing
方法,因为这与问题无关,但你可以在这里找到它:http://api.mongodb.org/python/current/examples/custom_type.html)
Edit: dict中的key的值是list类型会有问题。出于某种原因,pymongo 没有将它传递给 SONManipulator
。所以列表没有转换。
我已经更新了 class 来处理这个问题(但我没有为 sets
和 tuples
做)。
class MigrationTransformer(SONManipulator):
def _encode_date(self, value):
return datetime.datetime.combine(
value,
datetime.datetime.min.time())
def _handle_list(self, value):
for index, item in enumerate(value):
if isinstance(item, dict):
value[index] = self._handle_dict(item)
elif isinstance(item, list):
value[index] = self._handle_list(item)
elif isinstance(item, datetime.date):
value[index] = self._encode_date(item)
return value
def _handle_dict(self, item):
for (key, value) in item.items():
if type(value) == datetime.date:
item[key] = self._encode_date(value)
elif isinstance(value, dict): # recurse into sub-docs
item[key] = self._handle_dict(value)
elif isinstance(value, list): # recurse into sub-docs
item[key] = self._handle_list(value)
return item
def transform_incoming(self, son, collection):
for (key, value) in son.items():
# datetime.datetime is instance of datetime.date
# compare type explicitly only
if type(value) == datetime.date:
son[key] = self._encode_date(value)
elif isinstance(value, dict): # recurse into sub-docs
son[key] = self.transform_incoming(value, collection)
elif isinstance(value, list): # recurse into sub-docs
son[key] = self._handle_list(value)
return son
只是替换
datetime.date.today()
和
datetime.datetime.today()
但注意前者有日期,后者有 return 日期时间
结果是
PyMongo doesn't support saving date instances. The server doesn't have a type for dates without times, so there would have to be some convention used to save dates without times. If you need to save a date your client should convert it to a datetime instance and you can save that.
This answer 声明这可以通过 datetime.datetime.combine
方法完成,如下所示:
datetime.datetime.combine(dateWithoutTime, datetime.time.min)