# 介绍mongodb auto reference
# author: luw2007@gmai.com
# 请在本地测试环境上使用
from pymongo import MongoClient
from pymongo.son_manipulator import AutoReference, NamespaceInjector
from bson import DBRef
DB_NAME = 'test'
PEOPLE_TABLE = 'people'
MSG_TABLE = 'msg'
# 没有添加自动引用的表, 方便查询原始的数据
no_reference_db = MongoClient()[DB_NAME]
raw_people = no_reference_db[PEOPLE_TABLE]
raw_msg = no_reference_db[MSG_TABLE]
# 清空历史数据
_ = raw_people.remove()
_ = raw_msg.remove()
# 连接到本地的mongodb, 并打开自动引用
db = MongoClient()[DB_NAME]
db.add_son_manipulator(AutoReference(db))
db.add_son_manipulator(NamespaceInjector())
people = db[PEOPLE_TABLE]
msg = db[MSG_TABLE]
# 新增
peter = {'name': 'peter'}
john = {'name': 'john'}
marry = {'name': 'marry'}
huangz = {'name': 'huangz', 'friends': [peter, john, marry]}
people.insert([peter, john, marry, huangz])
[ObjectId('54b7544e5b6d6e59c68eb972'), ObjectId('54b7544e5b6d6e59c68eb973'), ObjectId('54b7544e5b6d6e59c68eb974'), ObjectId('54b7544e5b6d6e59c68eb975')]
# 开启自动引用后, 会增加 ``{'_ns': 'people'}``
print(peter)
{'_ns': u'people', '_id': ObjectId('54b7544e5b6d6e59c68eb972'), 'name': 'peter'}
# 对比开启自动引用前后数据差异
# 数据库中是 DBRef类型的字段, 自动引用后将"DERef" 转换成对应的真实字段
#在数据库中
raw_people.find_one({'name': 'huangz'})['friends'][0]
DBRef(u'people', ObjectId('54b7544e5b6d6e59c68eb972'))
# 自动引用后
huangz['friends'][0]
{'_id': ObjectId('54b7544e5b6d6e59c68eb972'), '_ns': u'people', 'name': 'peter'}
# 搜索DBRef 字段
people.find_one({'friends': DBRef(PEOPLE_TABLE, peter['_id'])}, {'name': 1})
SON([(u'_id', ObjectId('54b7544e5b6d6e59c68eb975')), (u'name', u'huangz')])
# 删除 use $pull 删除掉数组中的DBRef
peter_ref = DBRef(PEOPLE_TABLE, peter['_id'])
people.update({'friends': peter_ref}, {'$pull': {'friends': peter_ref}})
{u'n': 1, u'nModified': 1, u'ok': 1, 'updatedExisting': True}
# 某条数据中即使有自动引用, 这条数据依然是普通的mongodb数据. 直接使用remove 就可以删除
people.remove(marry)
{u'n': 1, u'ok': 1}
'''由于mongodb 不提供事务, 而且目前自动引用不提供关联删除功能
所以自动引用中的对象删除了, 开启自动引用后会显示None, 因此删除时需要自行处理引用的情况.'''
print('haungz 中不会自动删除 friends中的marry字段, \n由 %r 变成 %r' % (
huangz['friends'][-1],
people.find_one({'_id': huangz['_id']})['friends'][-1])
)
haungz 中不会自动删除 friends中的marry字段, 由 {'_ns': u'people', '_id': ObjectId('54b7544e5b6d6e59c68eb974'), 'name': 'marry'} 变成 None
# 手工删除掉 friends 中的 'marry', 重新保存
huangz['friends'].pop()
people.save(huangz)
ObjectId('54b7544e5b6d6e59c68eb975')
# 此时数据中已经没有marry
people.find_one({'_id': huangz['_id']})['friends']
[SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb972')), (u'name', u'peter')]), SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb973')), (u'name', u'john')])]
# 跨表
msg.insert([{'from': huangz, 'to': peter, 'message': 'from hangz to peter'},
{'from': huangz, 'to': john, 'message': 'from hangz to john'},
{'from': huangz, 'to': marry, 'message': 'from hangz to marry'}])
[ObjectId('54b754535b6d6e59c68eb976'), ObjectId('54b754535b6d6e59c68eb977'), ObjectId('54b754535b6d6e59c68eb978')]
# 自动处理引用前
'''注意from, to 字段'''
raw_msg.find_one({'to': DBRef(PEOPLE_TABLE, peter['_id'])})
{u'_id': ObjectId('54b754535b6d6e59c68eb976'), u'_ns': u'msg', u'from': DBRef(u'people', ObjectId('54b7544e5b6d6e59c68eb975')), u'message': u'from hangz to peter', u'to': DBRef(u'people', ObjectId('54b7544e5b6d6e59c68eb972'))}
# 自动处理引用后
to_peter = msg.find_one({'to': DBRef(PEOPLE_TABLE, peter['_id'])})
print(to_peter)
SON([(u'to', SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb972')), (u'name', u'peter')])), (u'message', u'from hangz to peter'), (u'_id', ObjectId('54b754535b6d6e59c68eb976')), (u'from', SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb975')), (u'friends', [SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb972')), (u'name', u'peter')]), SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb973')), (u'name', u'john')])]), (u'name', u'huangz')])), (u'_ns', u'msg')])
'''注意 from.friends 字段也会被自动引用'''
to_peter['from']['friends']
[SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb972')), (u'name', u'peter')]), SON([(u'_ns', u'people'), (u'_id', ObjectId('54b7544e5b6d6e59c68eb973')), (u'name', u'john')])]