0

I'm trying group data for a web service.

The web service is running on Ruby on Rails and I'm working in my API controller (lets call it the index action of my projects_controller.

The table schema looks like this (the data types and example has been changed for NDA reasons). Unfortunately, the example here suggests that I break employee and projects into different tables, but please overlook that for now. This is the data that I am given:

COLUMNS:
employee, e_id, company, hire_date, project_name, project_due_date

ROWS:
John, 12345, XYZ, 01-01-2001, Project_A, 12-31-2012
John, 12345, XYZ, 01-01-2001, Project_B, 03-15-2013
John, 12345, XYZ, 01-01-2001, Project_C, 06-25-2013
Jane, 98765, XYZ, 05-22-2003, Project_Q, 01-15-2013
Jane, 98765, XYZ, 05-22-2003, Project_W, 02-25-2013
Jane, 98765, XYZ, 05-22-2003, Project_E, 08-01-2013

In order to reduce data transfer, I would like to return the above as follows:

[
    {
        "employee":"John",
        "e_id":"12345",
        "company":"XYZ",
        "hire_date":"01-01-2001",
        "projects":[
                     { "project_name":"Project_A", "project_due_date":"12-31-2012" },
                     { "project_name":"Project_B", "project_due_date":"03-15-2013" },
                     { "project_name":"Project_C", "project_due_date":"06-25-2013" }
                   ]
    },
    {
        "employee":"Jane",
        "e_id":"98765",
        "company":"XYZ",
        "hire_date":"05-22-2003",
        "projects":[
                     { "project_name":"Project_Q", "project_due_date":"01-15-2013" },
                     { "project_name":"Project_W", "project_due_date":"02-25-2013" },
                     { "project_name":"Project_E", "project_due_date":"08-01-2013" }
                   ]
    }
]

I can't seem to figure out the best way to group my SQL query results (rows) into the organized hash(es) that I have in the ideal data. I imagine I need some .each and hashes to post-process the data returned by my SQL call, but I can't seem to figure out the "Ruby" way (I'm also not a seasoned Ruby developer, so any reference links would also be appreciated so I can read up on the solution).

How can I accomplish this?

[EDIT]

I am performing a SQL query on the Project object. My controller is as follows:

def index
   sql = "SELECT employee, e_id, company, hire_date, project_name, project_due_date
     FROM projects
     AND created_at = (SELECT created_at FROM projects ORDER BY created_at DESC LIMIT 1)
     ORDER BY company, employee, project_due_date"

   result = Project.find_by_sql(sql)
   respond_with(result)
end

The data I am getting back is a bunch of Project objects in the following format

RUBY DEBUGGER:

(rdb:2) result
[#<Project employee: "John", e_id: 12345, company: "XYZ", hire_date: "01-01-2001", project_name: "Project_A", project_due_date: "12-31-2012">,
 #<Project employee: "John", e_id: 12345, company: "XYZ", hire_date: "01-01-2001", project_name: "Project_B", project_due_date: "03-15-2013">,
 #<Project employee: "John", e_id: 12345, company: "XYZ", hire_date: "01-01-2001", project_name: "Project_C", project_due_date: "06-25-2013">,
 #<Project employee: "Jane", e_id: 98765, company: "XYZ", hire_date: "05-22-2003", project_name: "Project_Q", project_due_date: "01-15-2013">,
 #<Project employee: "Jane", e_id: 98765, company: "XYZ", hire_date: "05-22-2003", project_name: "Project_W", project_due_date: "02-25-2013">,
 #<Project employee: "Jane", e_id: 98765, company: "XYZ", hire_date: "05-22-2003", project_name: "Project_E", project_due_date: "08-01-2013">]

[EDIT 2]

I know I can resolve this problem in a very naive, non-Ruby way, but I'd like to know the proper way to get it working. A basic solution could consist of iterating through the result array and parsing out the data row by row, saving the employee data to a temp hash and their project data to an array of hashes. When the iteration comes to a new employee, save the data for the previous employee data in an array and reset the temp array/hashes for the next employee. Very ugly, but very possible.

However, there MUST be a Ruby way. Please help!

4

1 回答 1

1

To produce the grouped data in the requested form:

grouped_data = data.group_by do |project|
  [project.employee, project.e_id, project.company, project.hire_date]
end.map do |k, v|
  { 
    "employee"  => k[0],
    "e_id"      => k[1],
    "company"   => k[2],
    "hire_date" => k[3],

    "projects" => v.map do |p|
      {
        "project_name"     => p.project_name,
        "project_due_date" => p.project_due_date
      }
    end
  }
end

And finally use to_json to produce the JSON formatted version, e.g.:

grouped_data.to_json
于 2012-11-18T22:32:41.643 回答