背景:
几个月前接触mongodb,整理总结工作中的思考,把遇到的问题及对应的方法写出来。
准备初始数据:
ret = test_coll.update_many(
{'username': 'liming',},
{"$set": {
'a.animal.dog': ['1', '2', '3', ],
'a.animal.cat': ['1', '2', '3', ],
'a.animal.pig': ['1', '2', '3', ],
} },
upsert=True
)
# liming同学调查a区域动物的 不同动物的 名称列表
# 这里使用update是为了方便看,防止放太多嵌套看了难受,这里使用insert是会报错的
目的:
查询dog动物的名称列表
查询方法:
# 方法一:
def query_dog_names(username):
return test_coll.find_one({'username': username}, {'a.animal.dog': 1, '_id': 0})
username = 'liming'
ret = query_dog_names(username)
# ret 的查询结果 {'a': {'animal': {'dog': ['1', '2', '3']}}}
dog_names = ret['a']['animal']['dog']
#要考虑查询没有匹配结果的情况
dog_names = ret['a']['animal']['dog'] if ret is not None else []
#方法二,想要查询的时候就是一个字典结构,比如{'dog': ['1', '2', '3']}:
def query_dog_names_method(username):
return test_coll.aggregate([
{"$match": {'username': username}},
{"$project": {'dog': '$a.animal.dog', '_id': 0}}
])
# 前一个dog为需要修改后的名字, '$a.animal.dog'取值
ret = list(query_dog_names_method(username))
dog_names_dict = ret[0] if ret else {}
#{'dog': ['1', '2', '3']}
#方法三:根据需要把 狗 猫 猪中的一种或者多种名单都查出来时
ALLOWED_TYPES = ['dog', 'cat', 'pig']
def query_animal_names(username, fields=None):
if fields and set(fields) - set(ALLOWED_TYPES):
raise ValueError('not support type')
match_clause = {"$match": {'username': username}}
project = {'_id': 0}
if fields:
project.update({k: '$a.animal.{}'.format(k) for k in fields})
return test_coll.aggregate([
match_clause,
{"$project": project}
])
ret = list(query_animal_names(username, fields=['dog', 'pig', 'cat']))
animal_names_dict = ret[0] if ret else {}
#{'dog': ['1', '2', '3'], 'pig': ['1', '2', '3'], 'cat': ['1', '2', '3']}
总结
mongodb 中aggregation的用法很多这里重点介绍将多级嵌套改名后返回的用户,在实际开发设计中,尽可能结构不要复杂,可以拍平,方面维护,实在是遇到多级嵌套时的查询,可以考虑一下 改名的用法,官方文档也非常详情,可见https://docs.mongodb.com/manual/reference/operator/aggregation/project/#pipe._S_project