python解决Mongodb 管道聚合后单文档16M限制

最近产品定位一个问题,因为代码里面使用了管道聚合(aggregate)后,导致几万个数据里面有超过16M的数据,从而报了一个"BSONobj is invaild. Size must between 0 and 16M"的一个错。百度了一下,上面说的是一个document文档最大尺寸为16M,而超过了16M后就要存到GridFS中,但是我们的mongodb不能修改表结构,不能重启,总之就是不能动,只能从代码方面着手了。
开始也有想过加一个参数{“allowDiskUse”: True},但是加了后发现没有用,具体原因是因为allowDiskUse是用于避免pipeline的stage的内存使用超过100mb而报错,而我遇到的限制是针对单个文件而言。下面是修改前的部分代码

pipeline = []
if match:
	pipline.append({'$match': match})
pipeline.append({"$group":{"_id":"$status","count":{$sum":1},"features":{"$push":{"$result.local"}}})
ret = {}
for x in Task.objects.aggregate(*pipeline):
	status = x['_id']
	if status not in ['finish', 'fail']:
		continue
	for result in x['features']:
		if not result:
			continue
		features = result.get('featureList before upgrade', dict())
		after = result.get('featureList after upgrade', dict())
		features.update(filter(lambda item:item[1], after.iteritems()))
		for k, v in features.iteritems():
			if k not in ret:
				ret[k] = {
					'name': k,
					'success':0,
					'failed':0
					}
				temp = ret[k]
				if v:
					if status =='finish':
						temp['success'] += 1
					elif status == 'failed':
						temp['failed'] += 1
return ret.values()
		

既然改数据库行不通,那只有从数据处理上着手了,查了下管道聚合的一些资料后,我发现有个"$unwind"的参数正是我需要的,它可以把聚合的数据里面的"features"给提取出来,而“features”里面的参数,正式导致数据超过16m的罪魁祸首,所以就在pipeline后面追加这个参数,把需要的数据分离出来。

pipeline = []
	if match:
		pipline.append({'$match': match})
	pipeline.append({"$group":{"_id":"$status","count":{$sum":1},"features":{"$push":{"$result.local"}}})
	pipeline.append({"$unwind": "$features"})
	ret = {}

分离开后,我们就可以提取出我们需要的一些信息出来了,因为最后需要一个字典,所以要提前先定义好,而“featureList before upgrade”和“featureList after upgrade”是我们需要做处理的大文件名:

if status not in ['finish', 'fail']:
			continue
		features = dict()
		after = dict()
		for result, values in x['features'].items():
			if not result:
				continue
			if result == "featureList before upgrade":
			features = dict(values)
			if result == "featureList after upgrade":
			after = dict(values)
			features.update(filter(lambda item:item[1], after.iteritems()))

至此,所有的聚合文档都被分离成小文件,而我们所遇到的问题也就迎刃而解了。因为要处理的数据量很大,有四万多条,而且每天都还在不断的更新,而我们采取的是flask和vue前后分离,导致页面刷新数据的时候比较慢,效率不太高,所以目前还在考虑有没有什么优化方案能够让页面刷新数据更快。

你可能感兴趣的:(python解决Mongodb 管道聚合后单文档16M限制)