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

492 lines
11 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.

/**
* 设备/用户忠诚度(粘性)统计模型
*/
const BaseMod = require('./base')
const Platform = require('./platform')
const Channel = require('./channel')
const Version = require('./version')
const SessionLog = require('./sessionLog')
const UserSessionLog = require('./userSessionLog')
const {
DateTime
} = require('../lib')
module.exports = class Loyalty extends BaseMod {
constructor() {
super()
this.tableName = 'loyalty-result'
this.platforms = []
this.channels = []
this.versions = []
}
/**
* 设备/用户忠诚度(粘性)统计
* @param {String} type 统计类型 hour实时统计 day按天统计week按周统计 month按月统计
* @param {Date|Time} date 指定日期或时间戳
* @param {Boolean} reset 是否重置为ture时会重置该批次数据
*/
async stat(type, date, reset) {
const allowedType = ['day']
if (!allowedType.includes(type)) {
return {
code: 1002,
msg: 'This type is not allowed'
}
}
this.fillType = type
const dateTime = new DateTime()
const dateDimension = dateTime.getTimeDimensionByType(type, -1, date)
this.startTime = dateDimension.startTime
this.endTime = dateDimension.endTime
if (this.debug) {
console.log('this time', dateTime.getTime())
console.log('dimension time', this.startTime + '--' + this.endTime)
}
// 查看当前时间段日志是否已存在,防止重复生成
if (!reset) {
const checkRes = await this.getCollection(this.tableName).where({
start_time: this.startTime,
end_time: this.endTime
}).get()
if (checkRes.data.length > 0) {
console.log('loyalty log have existed')
return {
code: 1003,
msg: 'This log have existed'
}
}
} else {
const delRes = await this.delete(this.tableName, {
start_time: this.startTime,
end_time: this.endTime
})
console.log('delete old data result:', JSON.stringify(delRes))
}
// 数据获取
this.sessionLog = new SessionLog()
const statRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
duration: 1,
create_time: 1
},
match: {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel'
},
page_count_sum: {
$sum: '$page_count'
},
duration_sum: {
$sum: '$duration'
}
},
sort: {
page_count_sum: 1,
duration_sum: 1
},
getAll: true
})
let res = {
code: 0,
msg: 'success'
}
if (this.debug) {
console.log('statRes', JSON.stringify(statRes))
}
if (statRes.data.length > 0) {
this.fillData = []
for (const i in statRes.data) {
await this.fill(statRes.data[i])
}
if (this.fillData.length > 0) {
res = await this.batchInsert(this.tableName, this.fillData)
}
}
return res
}
/**
* 设备/用户忠诚度(粘性)数据填充
* @param {Object} data 数据集合
*/
async fill(data) {
// 平台信息
let platformInfo = null
if (this.platforms && this.platforms[data._id.platform]) {
platformInfo = this.platforms[data._id.platform]
} else {
const platform = new Platform()
platformInfo = await platform.getPlatformAndCreate(data._id.platform, null)
if (!platformInfo || platformInfo.length === 0) {
platformInfo._id = ''
}
this.platforms[data._id.platform] = platformInfo
if (this.debug) {
console.log('platformInfo', JSON.stringify(platformInfo))
}
}
// 渠道信息
let channelInfo = null
const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel
if (this.channels && this.channels[channelKey]) {
channelInfo = this.channels[channelKey]
} else {
const channel = new Channel()
channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.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._id.appid + '_' + data._id.platform + '_' + data._id.version
if (this.versions && this.versions[versionKey]) {
versionInfo = this.versions[versionKey]
} else {
const version = new Version()
versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version)
if (!versionInfo || versionInfo.length === 0) {
versionInfo._id = ''
}
this.versions[versionKey] = versionInfo
if (this.debug) {
console.log('versionInfo', JSON.stringify(versionInfo))
}
}
// 访问深度-用户数统计和访问次数
const pageMark = [1, 2, 3, 4, [5, 10], [10]]
const matchCondition = Object.assign(data._id, {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
})
const visitDepthData = {
visit_devices: {},
visit_users: {},
visit_times: {}
}
const userSessionLog = new UserSessionLog()
//根据各访问页面数区间统计
for (const pi in pageMark) {
let pageMarkCondition = {
page_count: pageMark[pi]
}
if (Array.isArray(pageMark[pi])) {
if (pageMark[pi].length === 2) {
pageMarkCondition = {
page_count: {
$gte: pageMark[pi][0],
$lte: pageMark[pi][1]
}
}
} else {
pageMarkCondition = {
page_count: {
$gt: pageMark[pi][0]
}
}
}
}
// 访问次数(会话次数)统计
const searchCondition = {
...matchCondition,
...pageMarkCondition
}
const vistRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
create_time: 1
},
match: searchCondition,
group: {
_id: {},
total_visits: {
$sum: 1
}
}
})
if (this.debug) {
console.log('vistResCondtion', JSON.stringify(searchCondition))
console.log('vistRes', JSON.stringify(vistRes))
}
let vistCount = 0
if (vistRes.data.length > 0) {
vistCount = vistRes.data[0].total_visits
}
// 设备数统计
const deviceRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
create_time: 1,
device_id: 1
},
match: searchCondition,
group: [{
_id: {
device_id: '$device_id'
}
}, {
_id: {},
total_devices: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('searchCondition', JSON.stringify(searchCondition))
console.log('deviceRes', JSON.stringify(deviceRes))
}
let deviceCount = 0
if (deviceRes.data.length > 0) {
deviceCount = deviceRes.data[0].total_devices
}
// 用户数统计
const userRes = await this.aggregate(userSessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
create_time: 1,
uid: 1
},
match: searchCondition,
group: [{
_id: {
uid: '$uid'
}
}, {
_id: {},
total_users: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('userResCondtion', JSON.stringify(searchCondition))
console.log('userRes', JSON.stringify(userRes))
}
let userCount = 0
if (userRes.data.length > 0) {
userCount = userRes.data[0].total_users
}
const pageKey = 'p_' + (Array.isArray(pageMark[pi]) ? pageMark[pi][0] : pageMark[pi])
visitDepthData.visit_devices[pageKey] = deviceCount
visitDepthData.visit_users[pageKey] = userCount
visitDepthData.visit_times[pageKey] = vistCount
}
// 访问时长-用户数统计和访问次数
const durationMark = [
[0, 2],
[3, 5],
[6, 10],
[11, 20],
[21, 30],
[31, 50],
[51, 100],
[100]
]
const durationData = {
visit_devices: {},
visit_users: {},
visit_times: {}
}
//根据各访问时长区间统计
for (const di in durationMark) {
let durationMarkCondition = {
duration: durationMark[di]
}
if (Array.isArray(durationMark[di])) {
if (durationMark[di].length === 2) {
durationMarkCondition = {
duration: {
$gte: durationMark[di][0],
$lte: durationMark[di][1]
}
}
} else {
durationMarkCondition = {
duration: {
$gt: durationMark[di][0]
}
}
}
}
// 访问次数(会话次数)统计
const searchCondition = {
...matchCondition,
...durationMarkCondition
}
if (this.debug) {
console.log('searchCondition', JSON.stringify(searchCondition))
}
const vistRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
duration: 1,
create_time: 1
},
match: searchCondition,
group: {
_id: {},
total_visits: {
$sum: 1
}
}
})
if (this.debug) {
console.log('vistRes', JSON.stringify(vistRes))
}
let vistCount = 0
if (vistRes.data.length > 0) {
vistCount = vistRes.data[0].total_visits
}
// 设备数统计
const deviceRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
device_id: 1,
duration: 1,
create_time: 1
},
match: searchCondition,
group: [{
_id: {
device_id: '$device_id'
}
}, {
_id: {},
total_devices: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('userRes', JSON.stringify(deviceRes))
}
let deviceCount = 0
if (deviceRes.data.length > 0) {
deviceCount = deviceRes.data[0].total_devices
}
// 用户数统计
const userRes = await this.aggregate(userSessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
uid: 1,
duration: 1,
create_time: 1
},
match: searchCondition,
group: [{
_id: {
uid: '$uid'
}
}, {
_id: {},
total_users: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('userRes', JSON.stringify(userRes))
}
let userCount = 0
if (userRes.data.length > 0) {
userCount = userRes.data[0].total_users
}
const pageKey = 's_' + (Array.isArray(durationMark[di]) ? durationMark[di][0] : durationMark[di])
durationData.visit_devices[pageKey] = deviceCount
durationData.visit_users[pageKey] = userCount
durationData.visit_times[pageKey] = vistCount
}
// 数据填充
const datetime = new DateTime()
const insertParams = {
appid: data._id.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
visit_depth_data: visitDepthData,
duration_data: durationData,
stat_date: datetime.getDate('Ymd', this.startTime),
start_time: this.startTime,
end_time: this.endTime
}
this.fillData.push(insertParams)
return insertParams
}
}