Search code examples
structcoldfusioncfmlluceecfloop

Nested structures not sorted correctly


I am looping over a query, building an array of structures

<cffunction name="QueryConvert" returntype="any" output="false">
    <cfargument name="q" type="query" required="yes">
    <cfargument name="page" type="numeric" required="no" default="1">
    <cfargument name="rows" type="numeric" required="no" default="500">
    <cfset var result = structnew()>
    <cfset var rowStruct = structnew()>
    <cfset var col = "">
    <cfset result["page"] = arguments.page>
    <cfset result["total"] = ceiling(arguments.q.TotalrecordCount/arguments.rows)>
    <cfset result["records"] = arguments.q.TotalrecordCount>
    <cfset result["rows"] = arraynew(1)>
    <cfset queryDeleteColumn(arguments.q,'TotalrecordCount')>
    <cfset queryDeleteColumn(arguments.q,'rowNum')>
    <cfset columnLabels = QueryColumnArray(arguments.q)>
    <cfset rowStruct = [:]><!--- Tada an ordered struct --->
    <cfloop array="#columnLabels#" item="col">
         <cfset rowStruct[col] = q["#col#"]>
    </cfloop>
    <cfdump var="#result#" abort>
    <cfreturn result />
</cffunction>

but when I view the nested structures, the order of the keys is all mixed up. I expected them to match the order of the column names in the database table.


Solution

  • The short answer is you need to use a ordered struct. The long version looks like this:

    First we need to look at some sample data

     <cfscript>
     q = queryNew("id,name,category","Integer,Varchar,Varchar", 
         [{id=1, name="One", category="Cat"},{id=2, name="Two", category="Dog"}]
     );
    
    
     writedump(q);
     </cfscript>
    

    Let's look at out sample data. Note that the columns are not as expected.

    enter image description here

    Now let's get our columnLabels ready to go. Note that we are creating an array.

     </cfscript>
     result.rows = [];
    
     columnLabels = q.getMeta().getColumnLabels();
     writedump(columnLabels);
     </cfscript>
    

    enter image description here

    <cfloop query="q">
       <cfset rowStruct = [:]><!--- Tada an ordered struct --->
       <cfloop array="#columnLabels#" item="col">
           <cfset rowStruct[col] = q["#col#"]>
       </cfloop>
    
       <cfset arrayappend(result.rows, rowStruct)>
    </cfloop>
    
    <cfdump var="#result.rows#">
    

    Tada

    enter image description here

    Furthermore

    This is all easier to read with cfscript

    <cfscript>
    for (row in q)  {
        rowStruct = [:];
        for (col in columnLabels)    {
            rowStruct[col] = q["#col#"];
        }
        result.rows.append(rowStruct);
    }
    </cfscript>
    

    For a live version see: CFFiddle.com