I need to fill in a multiple value field with data that's currently split into multiple rows when I look at my view. Is there any easy way to combine these rows into a single row? Or maybe use one of the hooks to add in the additional field values into the existing node's field values?

I've attached a screenshot of the page view of my view. Notice how the "study guide" material is associated with different course nodes, but it's all the same material item. I really need those different course node id's to go into a single multi-value CCK nodereference field.

Comments

mikeryan’s picture

Assigned: Unassigned » mikeryan

The migrate module is inherently based on one input row from the view creating one object. To deal with multiple fields per object, you can do the work in the prepare_node hook. For the given study guide, query the course nodes related to it and fill them into the $node object. Something like:

function example_destination_prepare_node(&$node, $tblinfo, $row) {
  $errors = array();
  $sql = "SELECT cnm.nodeid 
          FROM {original_course_relation_table} oct 
          INNER JOIN {course_node_map} cnm ON oct.related_course_id=cnm.course_id
          WHERE oct.related_study_guide_id = %d";
  $result = db_query($sql, $row->study_guide_id);
  while ($row = db_fetch_object($result)) {
    $node->field_ref_course[$i++]['nid'] = $row->nodeid;
  }
  return $errors;
}

Does this help?

attheshow’s picture

Assigned: mikeryan » Unassigned

Awesome. I was struggling. I'll give this a shot and see if I can successfully implement it. Thanks Mike!

attheshow’s picture

StatusFileSize
new191.36 KB
new209.55 KB
new196.63 KB

So this is close to working for me, but for some reason, I can't seem to successfully fill in the node field with multiple values. I've attached some screenshots and here's the code I'm running for this node->type inside my prepare_node hook:

dsm($node);
      $sql = "SELECT ldb_610_Materials.MaterialID AS MaterialID,
   cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL.nodeid AS cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL_nodeid
 FROM cms_ldb_610_Materials ldb_610_Materials 
 INNER JOIN cms_ldb_630_MaterialsCourseREL ldb_630_MaterialsCourseREL_ldb_610_Materials ON ldb_610_Materials.MaterialID = ldb_630_MaterialsCourseREL_ldb_610_Materials.MaterialID
 INNER JOIN cms_cms_ldb_200_Courses_node_map cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL ON ldb_630_MaterialsCourseREL_ldb_610_Materials.CourseID = cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL.CourseID
 WHERE ldb_610_Materials.MaterialID = %d";
      $result = db_query($sql, $row->MaterialID);
      $rowCount = mysql_num_rows($result);
      while ($row2 = db_fetch_object($result)) {
        $node->field_course_nid[$i++]['nid'] = $row2->cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL_nodeid;
      }
      drupal_set_message('Updating node object now.');
      dsm($node);

My query is definitely working. The single "material" node that I'm importing has two courses associated with it, and those two values are being filled in the way that I mean for them to (you can see this in the "dsm_node_after_modification.png" screenshot). But when I go look at the node, the field doesn't appear to have the nid values in it. Any ideas of what might be wrong with this setup?

mikeryan’s picture

I was a little lazy - try $i = 0 before the loop...

attheshow’s picture

StatusFileSize
new193.93 KB

Ok, I tried making that adjustment. Now the "field_course_nid" array gets keys of 0 and 1 (see screenshot), but the result is the same. The actual field isn't being populated with the two values when the migration happens.

attheshow’s picture

I just looked through content.inc and saw a message that says:

 *  @todo
 *  Multiple values are not importing correctly yet -- CCK is creating
 *  three blank values before the valid values, so a fix to CCK is needed.
 *  Once fixed the idea is that multiple values can be imported into any 
 *  CCK field that has multiple values enabled by separating the values 
 *  with a double pipe (||).

Is that possibly the issue that I'm running into here?

attheshow’s picture

Status: Active » Fixed

Ok, I think I've got it working for the moment. Just in case anyone else wants to do this, here's the code I ended up using to fill in a multiple value field:

      $sql = "SELECT ldb_610_Materials.MaterialID AS MaterialID,
   cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL.nodeid AS cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL_nodeid
 FROM cms_ldb_610_Materials ldb_610_Materials 
 INNER JOIN cms_ldb_630_MaterialsCourseREL ldb_630_MaterialsCourseREL_ldb_610_Materials ON ldb_610_Materials.MaterialID = ldb_630_MaterialsCourseREL_ldb_610_Materials.MaterialID
 INNER JOIN cms_cms_ldb_200_Courses_node_map cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL ON ldb_630_MaterialsCourseREL_ldb_610_Materials.CourseID = cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL.CourseID
 WHERE ldb_610_Materials.MaterialID = %d";
      $result = db_query($sql, $row->MaterialID);
      $rowCount = mysql_num_rows($result);
      $x = 0;
      while ($row2 = db_fetch_object($result)) {
        if ($x == 0) {
          $node->field_material_course_nid = $row2->cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL_nodeid;
        } elseif ($x > 0) {
          $node->field_material_course_nid .= "||".$row2->cms_ldb_200_Courses_node_map_ldb_630_MaterialsCourseREL_nodeid;
        }
        $x++;
      }

Also, I highly recommend using Views to create the query that you need and then copy/paste it into your hook here.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

robertdouglass’s picture

Here's the code I used to do multiple value fields, in case it helps someone:

/**
 * This function which implements hook_migrate_destination, is primarily
 * for doing the footwork needed with multiple value fields. The query
has
 * to be done manually and the $node object has to be built in the
proper way.
 * Furthermore, this function has to handle all content types, so it is
likely
 * to get quite long.
 */
function mycustom_migrate_destination_prepare_node(&$node, $tblinfo, $row) {
  switch ($node->type) {
    case 'story':
      $node->field_story_category = array();
      db_set_active('sourcenews');
      $result = db_query("SELECT c.CatID FROM {news} n 
        LEFT JOIN {newstocat} c on n.id = c.NewsID WHERE n.id = %d", $row->id);
      while ($ids = db_fetch_object($result)) {
        $node->field_story_category[] = array('value' => $ids->CatID);
      }
      db_set_active('default');
      break;

    case 'profile';
      db_set_active('sourcemember');
      $question_map = array(
        29 => 'field_user_focus',
        30 => 'field_user_position',
        33 => 'field_user_how_found',
   );

      $memid = $row->MemID;
      foreach ($question_map as $QuestionID => $field) {
        $result = db_query("SELECT q.QuestionAvalAnsID FROM {memberanswer} m 
          INNER JOIN {questionavalans} q ON m.AnswerValue = q.AnswerText 
          WHERE m.MemID = '%s' AND m.QuestionID = %d", $memid, $QuestionID);
        while ($ids = db_fetch_object($result)) {
          $node->{$field}[] = array('value' => $ids->QuestionAvalAnsID);
        }
      }
      db_set_active('default');
      break;
  }
}

// This function makes a Drupal username out of the source first name + last name
function mycustom_migrate_destination_prepare_user(&$user, $tblinfo, $row) {
  $user['name'] = $row->member_FirstName . ' ' . $row->member_LastName;
}