Goal: Recursively remove all nulls and empty items from a document.
- 
This function removeNullObjectsAndElements will recursively prune nulls and empty items from a given JSON document.
 - 
Requires Eventing Storage (or metadata collection) and a "source" collection.
 - 
Will operate on all documents where doc.type === "my_data_to_prune".
 - 
This function is a superset of the cleanup functionality found in the Scriptlet removeObjectStubs.
 
- 
removeNullObjectsAndElements
 - 
Input Data/Mutation
 - 
Output Data/Mutation
 
// To run configure the settings for this Function, removeNullObjectsAndElements, 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 removeNullParts(obj) {
    // remove any null Objects
    Object.keys(obj).forEach(k =>
        (obj[k] && typeof obj[k] === 'object') && removeNullParts(obj[k]) ||
        (!obj[k] && obj[k] !== undefined) && delete(obj[k]) // 6.6+ can use "delete obj[k]""
    );
    Object.keys(obj).forEach(k =>
        (obj[k] && Array.isArray(obj[k])) &&
        (obj[k] = obj[k].filter(element => element !== null))
    );
    return obj;
}
function removeEmptyParts(obj) {
    if (obj !== null && typeof obj == "object") {
        Object.entries(obj).forEach(([k, v]) => {
            if (obj[k] && typeof obj[k] === 'object') {
                // recurse
                removeEmptyParts(obj[k])
                // collapse out null's in Array if any
                if (obj[k] && Array.isArray(obj[k])) {
                    obj[k] = obj[k].filter(element => element !== null)
                }
                // remove empty [] array items and {} object items
                if (
                    (obj[k] && Array.isArray(obj[k]) && obj[k].length === 0) ||
                    (obj[k] && !Array.isArray(obj[k]) && Object.keys(obj[k]).length === 0)
                ) {
                    delete(obj[k]) // 6.6+ can use "delete obj"
                }
            }
        });
    } else {
        // obj is a number or a string
    }
    return obj;
}
function OnUpdate(doc, meta) {
    if (doc.type !== "my_data_to_prune") return;
    // make a new doc without any nulls
    var newdoc = removeNullParts(doc);
    // make a new doc without {} [] empties
    newdoc = removeEmptyParts(newdoc);
    // alias src_col to our source collection. Since rev 6.5+ allowed to be in r/w mode
    src_col[meta.id] = newdoc;
}
INPUT: KEY my_data_to_prune::1001
{
  "type": "my_data_to_prune",
  "id": 1001,
  "a_first_super_long_name_right_here": 111,
  "b": "my object",
  "c": "",
  "d": null,
  "f": {
    "v": 1,
    "x": "",
    "y": null,
    "m": {
      "a": "asd"
    }
  },
  "f2": {
    "v": 1,
    "x": "",
    "y": null,
    "m": {
      "a": "asd",
      "b": null,
      "c": null,
      "a_second_super_long_name_right_here": 222,
      "ary1": [
        null,
        1,
        null,
        2,
        null,
        3
      ],
      "ary2": [
        [
          1,
          2
        ],
        [
          3,
          4
        ],
        [
          5,
          null,
          6
        ],
        {
          "a": 1
        },
        {
          "b": 2
        },
        {
          "c": 3,
          "d": null
        },
        {
          "e": null
        },
        [
          null,
          null,
          null,
          null
        ]
      ]
    }
  },
  "a_third_super_long_name_right_here": {
    "x": 1,
    "y": 2,
    "z": null
  }
}
UPDATED/OUTPUT: KEY my_data_to_prune::1001
{
  "type": "my_data_to_prune",
  "id": 1001,
  "a_first_super_long_name_right_here": 111,
  "b": "my object",
  "f": {
    "v": 1,
    "m": {
      "a": "asd"
    }
  },
  "f2": {
    "v": 1,
    "m": {
      "a": "asd",
      "a_second_super_long_name_right_here": 222,
      "ary1": [
        1,
        2,
        3
      ],
      "ary2": [
        [
          1,
          2
        ],
        [
          3,
          4
        ],
        [
          5,
          6
        ],
        {
          "a": 1
        },
        {
          "b": 2
        },
        {
          "c": 3
        }
      ]
    }
  },
  "a_third_super_long_name_right_here": {
    "x": 1,
    "y": 2
  }
}