123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /**
- * @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
- }
- }
|