Function: dateToEpochConversion
Goal: Recursively change String Dates into Unix Epoch timestamps.
-
This function dateToEpochConversion will recursively convert string dates to a UNIX Epoch timestamp.
-
The sample can convert to either seconds from Epoch or milliseconds from Epoch.
-
In addition the sample optionally rename fields by adding _ms or _sec suffix (note, arrays will not be renamed).
-
Requires Eventing Storage (or metadata collection) and a "source" collection.
-
Will operate on all documents where doc.type === "my_data_type".
// To run configure the settings for this Function, dateToEpochConversion, as follows:
//
// Version 7.1+
// "Function Scope"
// *.* (or try bulk.data if non-privileged)
// Version 7.0+
// "Listen to Location"
// bulk.data.source
// "Eventing Storage"
// rr100.eventing.metadata
// Binding(s)
// 1. "binding type", "alias name...", "bucket.scope.collection", "Access"
// "bucket alias", "src_col", "bulk.data.source", "read and write"
//
// Version 6.X
// "Source Bucket"
// source
// "MetaData Bucket"
// metadata
// Binding(s)
// 1. "binding type", "alias name...", "bucket", "Access"
// "bucket alias", "src_col", "source", "read and write"
function convertStrToEpoch(key, val, control) {
// We want to convert string dates to a Epoch tstamp, first we utilize
// a regex to filter, then if that passes we use Date.parse(..)
// to convert string to numeric timestamps, finally if the last argument
// is 'true' then add a suffix of "_ms" or "_sec" to the field name.
// Date.parse("2009/06/29 13:30:10", "yyyy/MM/dd HH:mm:ss");
// Date.parse("2020-06-24 09.55.22 -07:00", "yyyy-MM-dd HH:mm:ss Z");
// uses a self explanatory control document as follows:
// var control = [
// { "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+$/g, "millis": true, "rename": true },
// { "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/g, "millis": false, "rename": true }
// ];
for (var i=0;i<control.length;i++) {
var regxres = val.match(control[i].regx);
if (regxres !== null) {
var dt = Date.parse(val);
if (dt && dt !== null && !isNaN(dt)) {
var suffix = "";
var epochMs = dt // .getTime();
if (key !== "" && control[i].rename) {
if (control[i].millis) {
suffix = "_ms";
} else {
suffix = "_sec";
}
}
if (control[i].millis) {
val = epochMs;
} else {
val = Math.round(epochMs / 1000);
}
return { "key": key + suffix, "val": val, "epoch_ok": true };
}
}
}
return { "key": key, "val": val, "epoch_ok": false };
}
function converTsStringsToEpochNumbers(obj, control) {
// This does a deepCopy or deepClone but applies convertStrToEpoch where needed
// process terminal strings
if (obj && typeof obj === 'string') {
var retval = convertStrToEpoch("", obj, control);
if (retval.epoch_ok) obj = retval.val;
return obj;
}
if (!obj || typeof obj !== 'object') {
return obj;
}
// process Object
let newObj = {};
if (Array.isArray(obj)) {
newObj = obj.map(item => converTsStringsToEpochNumbers(item, control));
} else {
Object.keys(obj).forEach((k) => {
var retval = { "key": k, "val": obj[k] };
if (obj[k] && typeof obj[k] === 'string') {
retval = convertStrToEpoch(k, obj[k], control);
}
return newObj[retval.key] = converTsStringsToEpochNumbers(retval.val, control);
})
}
return newObj;
}
function OnUpdate(doc, meta) {
if (doc.type !== "my_data_type") return;
var rename_with_ms_or_sec = true; // rename our fields
// Apply four (4) different datetime search patterns across the entire document
var control = [
{ "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+$/g, "millis": true, "rename": true },
{ "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/g, "millis": false, "rename": true },
{ "regx": /^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.\d+ .\d\d:\d\d$/g, "millis": false, "rename": true },
{ "regx": /^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d .\d\d:\d\d$/g, "millis": true, "rename": true }
];
var newdoc = converTsStringsToEpochNumbers(doc, control);
// alias src_col to our source collection. Will work since rev 6.5+ allowed to be in r/w mode
src_col[meta.id] = newdoc;
}
INPUT: KEY my_data_type::1001
{
"type": "my_data_type",
"id": 1001,
"datet1a": "2009/06/29 13:30:10",
"datet1b": "2009/06/29 13:30:10",
"datet1c": "2009/06/29 13:30:10 -07:00",
"datet1d": "2009/06/29 13:30:10 -06:00",
"datet2a": "2009-06-29 13:30:10.333",
"datet2b": "2009-06-29 13:30:10.333",
"datet2c": "2009-06-29 13:30:10.333 -07:00",
"datet2d": "2009-06-29 13:30:10.333 -06:00",
"subdoc_same_dates": {
"datet1a": "2009/06/29 13:30:10",
"datet1b": "2009/06/29 13:30:10",
"datet1c": "2009/06/29 13:30:10 -07:00",
"datet1d": "2009/06/29 13:30:10 -06:00",
"datet2a": "2009-06-29 13:30:10.333",
"datet2b": "2009-06-29 13:30:10.333",
"datet2c": "2009-06-29 13:30:10.333 -07:00",
"datet2d": "2009-06-29 13:30:10.333 -06:00",
"subsubdoc_two_dates": {
"datet1a": "2009/06/29 13:30:10",
"datet1b": "2009/06/29 13:30:10",
"dary": [
"2009/06/29 13:30:10",
"2009-06-29 13:30:10.333",
{ "datet1a": "2009/06/29 13:30:10" }
]
}
}
}
UPDATED/OUTPUT: KEY my_data_type::1001
{
"type": "my_data_type",
"id": 1001,
"datet1a_sec": 1246307410,
"datet1b_sec": 1246307410,
"datet1c_ms": 1246307410000,
"datet1d_ms": 1246303810000,
"datet2a_ms": 1246307410333,
"datet2b_ms": 1246307410333,
"datet2c_sec": 1246307410,
"datet2d_sec": 1246303810,
"subdoc_same_dates": {
"datet1a_sec": 1246307410,
"datet1b_sec": 1246307410,
"datet1c_ms": 1246307410000,
"datet1d_ms": 1246303810000,
"datet2a_ms": 1246307410333,
"datet2b_ms": 1246307410333,
"datet2c_sec": 1246307410,
"datet2d_sec": 1246303810,
"subsubdoc_two_dates": {
"datet1a_sec": 1246307410,
"datet1b_sec": 1246307410,
"dary": [
1246307410,
1246307410333,
{
"datet1a_sec": 1246307410
}
]
}
}
}