---
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}
}
```