Search code examples
multidimensional-arraycoldfusion

Creating a function in Coldfusion to dynamically convert a multidimensional array to a query object


The problem I'm running into is the API I'm using for this particular project uses periods in the keys which is not allowed in query column names. So I need to figure out a way to rename the array keys to remove the periods (or replace them with an underscore). Here is the code I have so far, which is working, but throws an error when hitting the "accumulator.addRow" line. The error being that periods aren't allowed in column names.

<cfset varResults = '[{"roW_NUMBER":1,"membership.Individual.LocalID":999,"membership.Individual.FirstName":"AA","membership.Individual.LastName":"AA","membership.Individual.Company":null,"membership.Individual.Work_Address_Line1":"aaaa","membership.Individual.Work_Address_Line2":null,"membership.Individual.Work_Address_City":"Alexandria","membership.Individual.Work_Address_State":"VA","membership.Individual.Work_Address_PostalCode":"9999-2518","membership.Individual.Work_Address_CountryName":"UNITED STATES","membership.Individual.EmailAddress":"[email protected]","membership.Type.Name":"Regular","membership.JoinDate":"2009-05-01T00:00:00","membership.ExpirationDate":"2023-04-30T00:00:00","membership.Individual.FellowElectDate__c":null,"chapter.Name":"DDDD","id":"0e04bc98-0074-cc58-bf6a-0b438d800e7d"},{"roW_NUMBER":2,"membership.Individual.LocalID":9998,"membership.Individual.FirstName":"AA","membership.Individual.LastName":"AA","membership.Individual.Company":null,"membership.Individual.Work_Address_Line1":"ASASASAAASAS","membership.Individual.Work_Address_Line2":null,"membership.Individual.Work_Address_City":"Washington","membership.Individual.Work_Address_State":"DC","membership.Individual.Work_Address_PostalCode":"9999","membership.Individual.Work_Address_CountryName":"UNITED STATES","membership.Individual.EmailAddress":"[email protected]","membership.Type.Name":"Regular","membership.JoinDate":"2020-01-01T00:00:00","membership.ExpirationDate":"2022-12-31T00:00:00","membership.Individual.FellowElectDate__c":null,"chapter.Name":"DDDD","id":"0e04bc98-0074-c1ae-f171-0b438d800e7c"}]'>
<cfscript>
    function arrayToQuery(varChapterRoster) {
        return varChapterRoster.reduce(function(accumulator, element) {
            element.each(function(key) {
                if (!accumulator.keyExists(replace(key,".","_","all"))) {
                    accumulator.addColumn(replace(key,".","_","all"), []);
                }
            });
            //writeDump(element);
            accumulator.addRow(element);
            return accumulator;
        }, QueryNew(""));
    }
    // writeDump(varChapterRoster);
    writeDump(arrayToQuery(varChapterRoster));
</cfscript>

Specific error: Column names must be valid variable names. They must start with a letter and can only include letters, numbers, and underscores.

I got past the "keyexists" and "addcolumn" lines by using the replace function, but replace won't work on "element" (throws an error) on the addRow line.

Changing tactics, here is a CFFiddle with some dummy data in it of the method I'm trying now. I think it is more straight forward, but getting another error that I bet is related to the periods again.


Solution

  • <cfset varResults = '[{"roW_NUMBER":1,"membership.Individual.LocalID":999,"membership.Individual.FirstName":"AA","membership.Individual.LastName":"AA","membership.Individual.Company":null,"membership.Individual.Work_Address_Line1":"aaaa","membership.Individual.Work_Address_Line2":null,"membership.Individual.Work_Address_City":"Alexandria","membership.Individual.Work_Address_State":"VA","membership.Individual.Work_Address_PostalCode":"9999-2518","membership.Individual.Work_Address_CountryName":"UNITED STATES","membership.Individual.EmailAddress":"[email protected]","membership.Type.Name":"Regular","membership.JoinDate":"2009-05-01T00:00:00","membership.ExpirationDate":"2023-04-30T00:00:00","membership.Individual.FellowElectDate__c":null,"chapter.Name":"DDDD","id":"0e04bc98-0074-cc58-bf6a-0b438d800e7d"},{"roW_NUMBER":2,"membership.Individual.LocalID":9998,"membership.Individual.FirstName":"AA","membership.Individual.LastName":"AA","membership.Individual.Company":null,"membership.Individual.Work_Address_Line1":"ASASASAAASAS","membership.Individual.Work_Address_Line2":null,"membership.Individual.Work_Address_City":"Washington","membership.Individual.Work_Address_State":"DC","membership.Individual.Work_Address_PostalCode":"9999","membership.Individual.Work_Address_CountryName":"UNITED STATES","membership.Individual.EmailAddress":"[email protected]","membership.Type.Name":"Regular","membership.JoinDate":"2020-01-01T00:00:00","membership.ExpirationDate":"2022-12-31T00:00:00","membership.Individual.FellowElectDate__c":null,"chapter.Name":"DDDD","id":"0e04bc98-0074-c1ae-f171-0b438d800e7c"}]'>
    <cfset varResults = replace(varResults,":null",':""',"All")>
    <cfset varResults = replace(varResults,"T00:00:00","","All")>
    <cfset varResults = deserializeJSON(varResults)>
    

    Answer based on original post. Demo

    <cfscript>
        function arrayToQuery(varChapterRoster) {
            if(varChapterRoster.len() == 0){
                return QueryNew('');
            }
            return varChapterRoster.reduce(function(accumulator, element) {
                Row = QueryAddRow(accumulator);
                element.each(function(key) {
                    QuerySetCell( accumulator , replace(key,".","_","all") , element[key] , Row );
                });
                return accumulator;
            }, QueryNew(replace(StructKeyList(varResults[1]),".","_","all")));
        }
        // writeDump(varChapterRoster);
        writeDump(arrayToQuery(varResults));
    </cfscript>
    

    Answer based on your cffiddle. Demo

    <cfif NOT ArrayLen(varResults)>
        <cfthrow message="No data" />
    </cfif>
    
    <cfset Q = QueryNew( replace(StructKeyList(varResults[1]),".","_","all") ) />
    
    <cfloop index="item" array="#varResults#">
        <cfset Row = QueryAddRow(Q) />
        <cfloop item="ColName" collection="#item#" >
            <cfset QuerySetCell( Q , replace(ColName,".","_","all") , item[ColName] , Row ) />
        </cfloop>
    </cfloop>
    
    <cfdump var=#Q# />