NGTools/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/activeDevices.js
ldeyun 9dbfdc6c71 V1.0.0
微信小程序运行成功;
H5运行成功
2024-09-30 01:30:39 +08:00

529 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @class ActiveDevices 活跃设备模型 - 每日跑批合并,仅添加本周/本月首次访问的设备。
*/
const BaseMod = require('./base')
const Platform = require('./platform')
const Channel = require('./channel')
const Version = require('./version')
const SessionLog = require('./sessionLog')
const {
DateTime,
UniCrypto
} = require('../lib')
module.exports = class ActiveDevices extends BaseMod {
constructor() {
super()
this.tableName = 'active-devices'
this.platforms = []
this.channels = []
this.versions = []
}
/**
* @desc 活跃设备统计 - 为周统计/月统计提供周活/月活数据
* @param {date|time} date
* @param {bool} reset
*/
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: 'Devices 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 sessionLog = new SessionLog()
const statRes = await this.aggregate(sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
is_first_visit: 1,
create_time: 1,
device_id: 1
},
match: {
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel',
device_id: '$device_id'
},
is_new: {
$max: '$is_first_visit'
},
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
const statOldRes = await this.aggregate(sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
is_first_visit: 1,
create_time: 1,
old_device_id: 1
},
match: {
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
},
old_device_id: {$exists: true}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel',
old_device_id: '$old_device_id'
},
create_time: {
$min: '$create_time'
}
},
sort: {
create_time: 1
},
getAll: true
})
if (this.debug) {
console.log('statOldRes', JSON.stringify(statOldRes))
}
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,
device_ids: [],
old_device_ids: [],
info: [],
old_info: []
}
statData[statKey].device_ids.push(data._id.device_id)
statData[statKey].info[data._id.device_id] = {
is_new: data.is_new,
create_time: data.create_time
}
} else {
statData[statKey].device_ids.push(data._id.device_id)
statData[statKey].info[data._id.device_id] = {
is_new: data.is_new,
create_time: data.create_time
}
}
}
if(statOldRes.data.length) {
const oldDeviceIds = []
for(const osti in statOldRes.data) {
if(!statOldRes.data[osti]._id.old_device_id) {
continue
}
oldDeviceIds.push(statOldRes.data[osti]._id.old_device_id)
}
if(oldDeviceIds.length) {
const statOldDidRes = await this.aggregate(sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
is_first_visit: 1,
create_time: 1,
device_id: 1
},
match: {
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
},
device_id: {$in: oldDeviceIds}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel',
old_device_id: '$device_id'
},
create_time: {
$min: '$create_time'
}
},
sort: {
create_time: 1
},
getAll: true
})
if(statOldDidRes.data.length){
for(const osti in statOldDidRes.data) {
data = statOldDidRes.data[osti]
statKey = uniCrypto.md5(data._id.appid + data._id.platform + data._id.version + data._id
.channel)
if(!data._id.old_device_id) {
continue
}
if (!statData[statKey]) {
statData[statKey] = {
appid: data._id.appid,
platform: data._id.platform,
version: data._id.version,
channel: data._id.channel,
device_ids: [],
old_device_ids: [],
old_info: []
}
statData[statKey].old_device_ids.push(data._id.old_device_id)
} else {
statData[statKey].old_device_ids.push(data._id.old_device_id)
}
if(!statData[statKey].old_info[data._id.old_device_id]) {
statData[statKey].old_info[data._id.old_device_id] = {
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
}
/**
* 获取填充数据
* @param {Object} data
*/
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)
const dateMonthDimension = datetime.getTimeDimensionByType('month', 0, this.startTime)
if(data.device_ids) {
// 取出本周已经存储的device_id
const weekHaveDeviceList = []
const haveWeekList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
device_id: {
$in: data.device_ids
},
dimension: 'week',
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
}, {
device_id: 1
})
if (haveWeekList.data.length > 0) {
for (const hui in haveWeekList.data) {
weekHaveDeviceList.push(haveWeekList.data[hui].device_id)
}
}
if (this.debug) {
console.log('weekHaveDeviceList', JSON.stringify(weekHaveDeviceList))
}
// 取出本月已经存储的device_id
const monthHaveDeviceList = []
const haveMonthList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
device_id: {
$in: data.device_ids
},
dimension: 'month',
create_time: {
$gte: dateMonthDimension.startTime,
$lte: dateMonthDimension.endTime
}
}, {
device_id: 1
})
if (haveMonthList.data.length > 0) {
for (const hui in haveMonthList.data) {
monthHaveDeviceList.push(haveMonthList.data[hui].device_id)
}
}
if (this.debug) {
console.log('monthHaveDeviceList', JSON.stringify(monthHaveDeviceList))
}
//数据填充
for (const ui in data.device_ids) {
//周活跃数据填充
if (!weekHaveDeviceList.includes(data.device_ids[ui])) {
this.fillData.push({
appid: data.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
is_new: data.info[data.device_ids[ui]].is_new,
device_id: data.device_ids[ui],
dimension: 'week',
create_time: data.info[data.device_ids[ui]].create_time
})
}
//月活跃数据填充
if (!monthHaveDeviceList.includes(data.device_ids[ui])) {
this.fillData.push({
appid: data.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
is_new: data.info[data.device_ids[ui]].is_new,
device_id: data.device_ids[ui],
dimension: 'month',
create_time: data.info[data.device_ids[ui]].create_time
})
}
}
}
if(data.old_device_ids) {
// 取出本周已经存储的old_device_id
const weekHaveOldDeviceList = []
const haveOldWeekList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
device_id: {
$in: data.old_device_ids
},
dimension: 'week-old',
create_time: {
$gte: dateDimension.startTime,
$lte: dateDimension.endTime
}
}, {
device_id: 1
})
if (haveOldWeekList.data.length > 0) {
for (const hui in haveOldWeekList.data) {
weekHaveOldDeviceList.push(haveOldWeekList.data[hui].device_id)
}
}
if (this.debug) {
console.log('weekHaveOldDeviceList', JSON.stringify(weekHaveOldDeviceList))
}
// 取出本月已经存储的old_device_id
const monthHaveOldDeviceList = []
const haveOldMonthList = await this.selectAll(this.tableName, {
appid: data.appid,
version_id: versionInfo._id,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
device_id: {
$in: data.old_device_ids
},
dimension: 'month-old',
create_time: {
$gte: dateMonthDimension.startTime,
$lte: dateMonthDimension.endTime
}
}, {
device_id: 1
})
if (haveOldMonthList.data.length > 0) {
for (const hui in haveOldMonthList.data) {
monthHaveOldDeviceList.push(haveOldMonthList.data[hui].device_id)
}
}
if (this.debug) {
console.log('monthHaveOldDeviceList', JSON.stringify(monthHaveOldDeviceList))
}
//数据填充
for (const ui in data.old_device_ids) {
//周活跃数据填充
if (!weekHaveOldDeviceList.includes(data.old_device_ids[ui])) {
this.fillData.push({
appid: data.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
is_new: 0,
device_id: data.old_device_ids[ui],
dimension: 'week-old',
create_time: data.old_info[data.old_device_ids[ui]].create_time
})
}
//月活跃数据填充
if (!monthHaveOldDeviceList.includes(data.old_device_ids[ui])) {
this.fillData.push({
appid: data.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
is_new: 0,
device_id: data.old_device_ids[ui],
dimension: 'month-old',
create_time: data.old_info[data.old_device_ids[ui]].create_time
})
}
}
}
return true
}
/**
* 日志清理,此处日志为临时数据并不需要自定义清理,默认为固定值即可
*/
async clean() {
// 清除周数据周留存统计最高需要10周数据多余的为无用数据
const weeks = 10
console.log('Clean device\'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 device\'s weekly logs - res:', res)
}
// 清除月数据月留存统计最高需要10个月数据多余的为无用数据
const monthes = 10
console.log('Clean device\'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 device\'s monthly logs - res:', res)
}
return monthRes
}
}