Skip to content

Instantly share code, notes, and snippets.

@PhearZero
Last active April 29, 2025 11:38
Show Gist options
  • Select an option

  • Save PhearZero/7382a00f301238dbe152e32c3681fd0b to your computer and use it in GitHub Desktop.

Select an option

Save PhearZero/7382a00f301238dbe152e32c3681fd0b to your computer and use it in GitHub Desktop.
BTree Info Dump

https://docs.couchdb.org/en/stable/ddocs/views/intro.html

Example captured delta of a Storekit Object (saved in CouchDB):

  • _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;
      })(),
    };
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment