昨天遇到一个需求:一个抽奖活动,参与的用户都有一个幸运值,幸运值是可以通过任务增加的,幸运值越高,中奖率越大(幸运用户5位)。
期初思路:用 sample 随机抽取幸运用户,sample 只能是随机筛选,没办法敢于,显然是不行的
中期思路:可不可以用聚合,在聚合阶段利用随机数乘以原始幸运值生成一个临时的幸运值,然后根据临时幸运值排序获取前5条数据,这样似乎可行,也没毛病。理论可行,开撸
const result = await db.collection('test_data')
.aggregate()
.project({
luck_num: 1,
name: 1,
temp_luck_num: $.multiply([Math.random(), '$luck_num'])
})
.sort({
temp_luck_num: -1,
})
.limit(5)
.end()
但是,结果却跟预想的有所偏差,经过分析,原因如下:在聚合计算阶段 temp_luck_num: $.multiply([Math.random(), '$luck_num'])中Math.random() 已经得出一个常数,也就是说效果跟 temp_luck_num: $.multiply([0.2365, '$luck_num'])是一样的,仍然无法达到随机的目的,temp_luck_num: $.multiply([para, '$luck_num']),初需要一个变量随机数,而此处的Math.random() 已经是是一个确切的值,好像陷入了一个死胡同。
最终解决方案:既然这个地方无法利用随机数进行计算,从数据源头解决是否可以?顺着这个思路终于想到一个办法:当用户参与抽奖的时候添加该用户抽奖信息时,直接生成一个随机数(temp_random),记录到用户抽奖信息中,开奖时利用 temp_random 及 luck_num 计算出临时幸运值,然后再排序获取。
const result = await db.collection('test_data')
.aggregate()
.project({
luck_num: 1,
name: 1,
temp_luck_num: $.multiply(["$temp_random", '$luck_num'])
})
.sort({
temp_luck_num: -1,
})
.limit(5)
.end()
如有更好的解决办法,请不吝赐教