---
title: "Function: genericFlatten"
description: Recursively and Generically Flatten a document for integration with
  a non-NOSQL RDBMS.
pubDate: 2026-08-17T09:53:44.266Z
antora:
  editUrl: https://github.com/couchbaselabs/docs-devex/edit/release/8.0/modules/eventing/pages/eventing-handler-genericFlatten.adoc
  xref: xref:server:eventing:eventing-handler-genericFlatten.adoc[]
---

[Consult the llms.txt file for a full list of contents](/llms.txt)
[View original HTML](/server/current/eventing/eventing-handler-genericFlatten.html)

# Function: genericFlatten

**Goal**: Recursively and Generically Flatten a document for integration with a non-NOSQL RDBMS.

* This function **genericFlatten** shows how a document can be flattened into a RDBMS importable record.
* Requires Eventing Storage (or metadata collection), a "source" collection, and a "destination" collection.
* Will operate on all documents where doc.type === "my\_data\_to\_flatten".
* Will write transformed or flattened documents to the destination collection with the same type and id.
* The destination collection can be shared (or replicated via XCDR to a business partner - maybe to AWS, GCP, or Azure).
* Will also remove the flattened document in the destination collection when the original source document is removed.
* Note since the document is not available during an OnDelete we will filter by KEY prefix starting with "my\_data\_to\_flatten:".

* genericFlatten
* Input Data/Mutation
* Output Data/Mutation

```javascript
// To run configure the settings for this Function, genericFlatten, 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", "dst_col",       "bulk.data.destination",   "read and write"
//
// Version 6.X
//   "Source Bucket"
//     source
//   "MetaData Bucket"
//     metadata
//   Binding(s)
//    1. "binding type", "alias name...", "bucket",     "Access"
//       "bucket alias", "dst_col",       "destinaton", "read and write"

function deepFlatten(obj,flatDoc, path) {
    if (!obj || typeof obj !== 'object') {
        // log("terminal", path, obj);
        // remove leading "_" and store the path as a key to the terminal value
        flatDoc[path.substr(1)] = obj;
        return obj;
    }
    // process Object
    let newObj = {};
    if (Array.isArray(obj)) {
        for (var i=0; i<= obj.length; i++ ) {
            newObj[i] = deepFlatten(obj[i], flatDoc, path + "_" + i)
        }
    } else {
        Object.keys(obj).forEach((k) => {
            return newObj[k] = deepFlatten(obj[k], flatDoc, path + "_" + k);
        })
    }
    return newObj;
}

function OnUpdate(doc, meta) {
    if (doc.type !== "my_data_to_flatten") return;

    var flatDoc = {};
    deepFlatten(doc,flatDoc,"");

    // alias src_bkt to our source bucket. Since rev 6.5+ allowed to be in r/w mode
    dst_col[meta.id] = flatDoc;
}

function OnDelete(meta, options) {
    // filter
    if (!(meta.id.startsWith("my_data_to_flatten:"))) return;

    log("OnDelete expired=" + options.expired +" REM id: "+meta.id);
    try {
        delete dst_col[meta.id];
    } catch (e) {
        log("Error on delete: "+e+", id:",meta.id);
    }
}
```

in keyspace bulk.data.source

```json
INPUT: KEY my_data_to_flatten::1001

{
  "type": "my_data_to_flatten",
  "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
  }
}
```

in keyspace bulk.data.destination

```json
UPDATED/OUTPUT: KEY my_data_to_flatten::1001

{
  "type": "my_data_to_flatten",
  "id": 1001,
  "a_first_super_long_name_right_here": 111,
  "b": "my object",
  "c": "",
  "d": null,
  "f_v": 1,
  "f_x": "",
  "f_y": null,
  "f_m_a": "asd",
  "f2_v": 1,
  "f2_x": "",
  "f2_y": null,
  "f2_m_a": "asd",
  "f2_m_b": null,
  "f2_m_c": null,
  "f2_m_a_second_super_long_name_right_here": 222,
  "f2_m_ary1_0": null,
  "f2_m_ary1_1": 1,
  "f2_m_ary1_2": null,
  "f2_m_ary1_3": 2,
  "f2_m_ary1_4": null,
  "f2_m_ary1_5": 3,
  "f2_m_ary2_0_0": 1,
  "f2_m_ary2_0_1": 2,
  "f2_m_ary2_1_0": 3,
  "f2_m_ary2_1_1": 4,
  "f2_m_ary2_2_0": 5,
  "f2_m_ary2_2_1": null,
  "f2_m_ary2_2_2": 6,
  "f2_m_ary2_3_a": 1,
  "f2_m_ary2_4_b": 2,
  "f2_m_ary2_5_c": 3,
  "f2_m_ary2_5_d": null,
  "f2_m_ary2_6_e": null,
  "f2_m_ary2_7_0": null,
  "f2_m_ary2_7_1": null,
  "f2_m_ary2_7_2": null,
  "f2_m_ary2_7_3": null,
  "a_third_super_long_name_right_here_x": 1,
  "a_third_super_long_name_right_here_y": 2,
  "a_third_super_long_name_right_here_z": null
}
```