You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
canteen/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeUsers.js

315 lines
7.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* @class ActiveUsers 活跃用户模型 - 每日跑批合并,仅添加本周/本月首次访问的用户。
*/
const BaseMod = require('./base')
const Platform = require('./platform')
const Channel = require('./channel')
const Version = require('./version')
const UserSessionLog = require('./userSessionLog')
const {
DateTime,
UniCrypto
} = require('../lib')
module.exports = class ActiveUsers extends BaseMod {
constructor() {
super()
this.tableName = 'active-users'
this.platforms = []
this.channels = []
this.versions = []
}
async stat(date, reset) {
const dateTime = new DateTime()
const dateDimension = dateTime.getTimeDimensionByType('day', -1, date)
this.startTime = dateDimension.startTime
// 查看当前时间段数据是否已存在,防止重复生成
if (!reset) {
const checkRes = await this.getCollection(this.tableName).where({
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
}).get()
if (checkRes.data.length > 0) {
console.log('data have exists')
return {
code: 1003,
msg: 'Users data in this time have already existed'
}
}
} else {
const delRes = await this.delete(this.tableName, {
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
})
console.log('Delete old data result:', JSON.stringify(delRes))
}
const userSessionLog = new UserSessionLog()
const statRes = await this.aggregate(userSessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
create_time: 1,
uid: 1
},
match: {
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel',
uid: '$uid'
},
create_time: {
$min: '$create_time'
}
},
sort: {
create_time: 1
},
getAll: true
})
let res = {
code: 0,
msg: 'success'
}
// if (this.debug) {
// console.log('statRes', JSON.stringify(statRes))
// }
if (statRes.data.length > 0) {
const uniCrypto = new UniCrypto()
// 同应用、平台、渠道、版本的数据合并
const statData = [];
let statKey;
let data
for (const sti in statRes.data) {
data = statRes.data[sti]
statKey = uniCrypto.md5(data._id.appid + data._id.platform + data._id.version + data._id
.channel)
if (!statData[statKey]) {
statData[statKey] = {
appid: data._id.appid,
platform: data._id.platform,
version: data._id.version,
channel: data._id.channel,
uids: [],
info: []
}
statData[statKey].uids.push(data._id.uid)
statData[statKey].info[data._id.uid] = {
create_time: data.create_time
}
} else {
statData[statKey].uids.push(data._id.uid)
statData[statKey].info[data._id.uid] = {
create_time: data.create_time
}
}
}
this.fillData = []
for (const sk in statData) {
await this.getFillData(statData[sk])
}
if (this.fillData.length > 0) {
res = await this.batchInsert(this.tableName, this.fillData)
}
}
return res
}
async getFillData(data) {
// 平台信息
let platformInfo = null
if (this.platforms && this.platforms[data.platform]) {
platformInfo = this.platforms[data.platform]
} else {
const platform = new Platform()
platformInfo = await platform.getPlatformAndCreate(data.platform, null)
if (!platformInfo || platformInfo.length === 0) {
platformInfo._id = ''
}
this.platforms[data.platform] = platformInfo
if (this.debug) {
console.log('platformInfo', JSON.stringify(platformInfo))
}
}
// 渠道信息
let channelInfo = null
const channelKey = data.appid + '_' + platformInfo._id + '_' + data.channel
if (this.channels && this.channels[channelKey]) {
channelInfo = this.channels[channelKey]
} else {
const channel = new Channel()
channelInfo = await channel.getChannelAndCreate(data.appid, platformInfo._id, data.channel)
if (!channelInfo || channelInfo.length === 0) {
channelInfo._id = ''
}
this.channels[channelKey] = channelInfo
if (this.debug) {
console.log('channelInfo', JSON.stringify(channelInfo))
}
}
// 版本信息
let versionInfo = null
const versionKey = data.appid + '_' + data.platform + '_' + data.version
if (this.versions && this.versions[versionKey]) {
versionInfo = this.versions[versionKey]
} else {
const version = new Version()
versionInfo = await version.getVersionAndCreate(data.appid, data.platform, data.version)
if (!versionInfo || versionInfo.length === 0) {
versionInfo._id = ''
}
this.versions[versionKey] = versionInfo
if (this.debug) {
console.log('versionInfo', JSON.stringify(versionInfo))
}
}
// 是否在本周内已存在
const datetime = new DateTime()
const dateDimension = datetime.getTimeDimensionByType('week', 0, this.startTime)
// 取出本周已经存储的uid
const weekHaveUserList = []
const haveWeekList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
uid: {
$in: data.uids
},
dimension: 'week',
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
}, {
uid: 1
})
if (this.debug) {
console.log('haveWeekList', JSON.stringify(haveWeekList))
}
if (haveWeekList.data.length > 0) {
for (const hui in haveWeekList.data) {
weekHaveUserList.push(haveWeekList.data[hui].uid)
}
}
// 取出本月已经存储的uid
const dateMonthDimension = datetime.getTimeDimensionByType('month', 0, this.startTime)
const monthHaveUserList = []
const haveMonthList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
uid: {
$in: data.uids
},
dimension: 'month',
create_time: {
$gte: dateMonthDimension.startTime,
$lte: dateMonthDimension.endTime
}
}, {
uid: 1
})
if (this.debug) {
console.log('haveMonthList', JSON.stringify(haveMonthList))
}
if (haveMonthList.data.length > 0) {
for (const hui in haveMonthList.data) {
monthHaveUserList.push(haveMonthList.data[hui].uid)
}
}
for (const ui in data.uids) {
if (!weekHaveUserList.includes(data.uids[ui])) {
this.fillData.push({
appid: data.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
uid: data.uids[ui],
dimension: 'week',
create_time: data.info[data.uids[ui]].create_time
})
}
if (!monthHaveUserList.includes(data.uids[ui])) {
this.fillData.push({
appid: data.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
uid: data.uids[ui],
dimension: 'month',
create_time: data.info[data.uids[ui]].create_time
})
}
}
return true
}
/**
* 日志清理,此处日志为临时数据并不需要自定义清理,默认为固定值即可
*/
async clean() {
// 清除周数据周留存统计最高需要10周数据多余的为无用数据
const weeks = 10
console.log('Clean user\'s weekly logs - week:', weeks)
const dateTime = new DateTime()
const res = await this.delete(this.tableName, {
dimension: 'week',
create_time: {
$lt: dateTime.getTimeBySetWeek(0 - weeks)
}
})
if (!res.code) {
console.log('Clean user\'s weekly logs - res:', res)
}
// 清除月数据月留存统计最高需要10个月数据多余的为无用数据
const monthes = 10
console.log('Clean user\'s monthly logs - month:', monthes)
const monthRes = await this.delete(this.tableName, {
dimension: 'month',
create_time: {
$lt: dateTime.getTimeBySetMonth(0 - monthes)
}
})
if (!monthRes.code) {
console.log('Clean user\'s monthly logs - res:', res)
}
return monthRes
}
}