--- tags: airaRetail --- ```js const HOUR = 3600000 const TIMEZONE_OFFSET = 8 * HOUR const dateOf = (millis) => { const isoDateTime = (new Date(millis + TIMEZONE_OFFSET)).toISOString() // 1970-01-01T00:00:00.000Z const [ date ] = isoDateTime.split("T") // 1970-01-01 return date.split("-").join("") // 19700101 } const hourOf = (millis) => { const isoDateTime = (new Date(millis + TIMEZONE_OFFSET)).toISOString() // 1970-01-01T00:00:00.000Z const [ _, time ] = isoDateTime.split("T") // 00:00:00.000Z const [ hour ] = time.split(":") // 00 return parseInt(hour) // 0 ~ 23 } const START_TIME = 1711296000000 // 臺灣時間 2024-03-25 00:00:00 const END_TIME = 1715788800000 // 臺灣時間 2024-05-16 00:00:00 const DAY = 86400000 function* allDates() { let millis = START_TIME while (millis <= END_TIME - 1) { yield { startTime: millis, endTime: millis + DAY - 1, } millis += DAY } } const typeOf = (age) => { if (age < 25) return "Age-1" if (age >= 25 && age < 35) return "Age-2" if (age >= 35 && age < 50) return "Age-3" return "Age-4" } const SOURCE = "DemographicRow" const count = (filter) => db[SOURCE].countDocuments(filter) const load = (filter, skip, limit) => db[SOURCE].find(filter).skip(skip).limit(limit) const addRecord = (stats, { timestamp: millis, uuid, deviceId, data_objects }) => { const hour = hourOf(millis) for (const { age } of data_objects) { if (!age) continue const type = typeOf(age) stats[uuid] = stats[uuid] || {} stats[uuid][deviceId] = stats[uuid][deviceId] || {} stats[uuid][deviceId][type] = stats[uuid][deviceId][type] || Array(24).fill(0) stats[uuid][deviceId][type][hour] += 1 } } const DESTINATION = "DemographicMeta" const save = (statId, $set) => db[DESTINATION].updateOne(statId, { $set }, { upsert: true }) const LIMIT = 2000 const main = () => { for (const { startTime, endTime } of allDates()) { const filter = { $and: [ { timestamp: { $gte: startTime} }, { timestamp: { $lte: endTime} }, ] } const total = count(filter) console.log({ total }) if (!total) continue const pages = Math.ceil(total / LIMIT) let page = 1 const stats = {} const dateCode = dateOf(startTime) while (page <= pages) { console.log(`date ${dateCode}, page ${page}/${pages}`) const skip = (page - 1) * LIMIT const cursor = load(filter, skip, LIMIT) while (cursor.hasNext()) addRecord(stats, cursor.next()) page += 1 } for (const uuid in stats) { // uuid:"IN"|"OUT" for (const deviceId in stats[uuid]) { // uuid:"camera-1" for (const type in stats[uuid][deviceId]) { // type: "Age-1" const statId = { dateCode, type, uuid, deviceId } const $set = { ...statId, data: stats[uuid][deviceId][type] } save(statId, $set) } } } } } main() ``` ``` { $and: [ {uuid: "IN"}, {deviceId: "camera-1"}, {"data_objects.0.age": {$exists: true}}, {"data_objects.0.age": {$gte: 25}}, {"data_objects.0.age": {$lt: 35}}, {"datetime": /^2024\/5\/14/} ] } ``` ```json { dateCode: { '$in': [ '20240331', '20240401', '20240402', '20240403', '20240404', '20240405', '20240406', '20240407', '20240408', '20240409', '20240410', '20240411', '20240412', '20240413', '20240414', '20240415', '20240416', '20240417', '20240418', '20240419', '20240420', '20240421', '20240422', '20240423', '20240424', '20240425', '20240426', '20240427', '20240428', '20240429', '20240430' ] }, uuid: { '$in': [ 'IN' ] } } ``` ```json { datetime: /^2024\/5\/15/, "data_objects.0.age": {$lt: 25} } ```