https://docs.couchdb.org/en/stable/ddocs/views/intro.html
- _id: <APPLICATION_ID>-<DELTA_ROUND_NUMBER>
{
"_id": "38389-3056",
"_rev": "1-fcd0372e6296f29e72ff8b91df379579",
"$type": "weather",
"$timestamp": 1745714968,
"humidity": {
"actual": 69,
"dewpoint": 2.75,
"relative": 33.75
},
"lux": 55395,
"pressure": 1117.5,
"rain": {
"rate": 961.25,
"total": 1025
},
"temperature": {
"air": -4.75,
"board": 10.75
},
"wind": {
"direction": 51,
"speed": 4641.5
}
}Then we map the object for historical data
(Key groups are type, box-key, year, month, day, hour, minute, second)
{"id":"38389-3056","key":["weather","humidity-actual",2025,4,27,0,49,28],"value":69},Using the following map function:
function (doc) {
if (typeof doc.$type === "string" && typeof doc.$timestamp === "number") {
const date = new Date(doc.$timestamp * 1000);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
Object.keys(doc).forEach((k)=>{
if(['_id', '_rev', '$timestamp', '$type'].includes(k)){
return
}
// TODO: recursive emit keys
if(typeof doc[k] === 'object'){
Object.keys(doc[k]).forEach((sk)=>{
emit([doc.$type, `${k}-${sk}`, year, month, day, hour, minute, second], doc[k][sk]);
})
} else {
emit([doc.$type, `${k}`, year, month, day, hour, minute, second], doc[k]);
}
})
}
}Which then can be reduced to OHLC values and other statistically signaficant data using any time range:
{"key":["weather","humidity-actual",2025],"value":{"o":53.5,"l":3.25,"h":100,"c":52,"sum":5397.25,"count":100,"sumsqr":359644.4375}},
{"key":["weather","humidity-dewpoint",2025],"value":{"o":-16.5,"l":-45.5,"h":48.75,"c":2.75,"sum":91.25,"count":100,"sumsqr":73575.6875}},
{"key":["weather","humidity-relative",2025],"value":{"o":85,"l":3,"h":100,"c":33.75,"sum":5137.5,"count":100,"sumsqr":346195.5}},
{"key":["weather","lux",2025],"value":{"o":58774,"l":374.75,"h":63664,"c":55395,"sum":3464207,"count":100,"sumsqr":156735924076.75}},
{"key":["weather","pressure",2025],"value":{"o":919,"l":870.25,"h":1193.75,"c":1117.5,"sum":102987.75,"count":100,"sumsqr":106977935.3125}},
{"key":["weather","rain-rate",2025],"value":{"o":1044,"l":882,"h":1192,"c":961.25,"sum":104222.75,"count":100,"sumsqr":109422300.5625}},
{"key":["weather","rain-total",2025],"value":{"o":1158,"l":872.5,"h":1198.25,"c":1025,"sum":104716.75,"count":100,"sumsqr":110547228.9375}},
{"key":["weather","temperature-air",2025],"value":{"o":24,"l":-49.75,"h":50,"c":-4.75,"sum":89.75,"count":100,"sumsqr":81887.8125}},
{"key":["weather","temperature-board",2025],"value":{"o":17.75,"l":-49.5,"h":49.5,"c":10.75,"sum":277.5,"count":100,"sumsqr":73140.125}},
{"key":["weather","wind-direction",2025],"value":{"o":57.75,"l":0.5,"h":359.75,"c":51,"sum":18420.25,"count":100,"sumsqr":4588098.3125}},
{"key":["weather","wind-speed",2025],"value":{"o":7475,"l":110.5,"h":9843.5,"c":4641.5,"sum":517918.75,"count":100,"sumsqr":3541704144.4375}}With the following Re-Reducer:
function (keys, values, rereduce) {
if (rereduce) {
return {
o: values[0].o,
l: values.reduce(function (a, b) {
return Math.min(a, b.l);
}, Infinity),
h: values.reduce(function (a, b) {
return Math.max(a, b.h);
}, -Infinity),
c: values[values.length - 1].c,
sum: values.reduce(function (a, b) {
return a + b.sum;
}, 0),
count: values.reduce(function (a, b) {
return a + b.count;
}, 0),
sumsqr: values.reduce(function (a, b) {
return a + b.sumsqr;
}, 0),
};
} else {
return {
o: values[0],
l: Math.min.apply(null, values),
h: Math.max.apply(null, values),
c: values[values.length - 1],
sum: sum(values),
count: values.length,
sumsqr: (function () {
var sumsqr = 0;
values.forEach(function (value) {
sumsqr += value * value;
});
return sumsqr;
})(),
};
}
}