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