What is migration?
If you want to use Drupal as a CMS over your existing proprietary or open source CMS, then you’ll have to go through the migration process.

The Drupal community provides an excellent framework called “Migrate” to simplify migration processes. The Migrate framework provides multiple ways to migrate source content into your Drupal site. JSON source migration is one of the most powerful methods of migration.

How is JSON migration better than any other migration method?
With the traditional method, we used to migrate content using a CSV file, which required a lot of tasks to be completed before source mapping, e.g:

  • CSV cleanup
  • Create a database using CSV file
  • Create a connection with source database
  • Write SQL queries to pull data from database (for this, you must have good skills in writing database queries)

Only after doing all this can we go ahead with migration steps, like field mapping, etc. This sounds like a big pain!

I’ve been thinking constantly about the future of Drupal migration without interacting with SQL, and having random off-and-on conversations with a few lead developers in my circles. I’d like to share my experience with JSON source migration, which helped me save a lot of time and effort in site migration.

How does JSON source migration help?
For JSON migration, we only need a JSON source URL. That’s it!

Let me show you how!

Prerequisite
Install the Migrate module from here: https://www.drupal.org/project/migrate
In this tutorial we’ll be creating a custom migration module to handle the migration process. In my case, I’ll be migrating movies from the JSON source to my Drupal movies content type, where I’ll be importing data into some text fields, taxonomy terms and an image field.

We will be using the following functions from the Migrate framework:

  • hook_migrate_api
  • MigrateSourceJSON
  • MigrateDestinationNode

Create custom module movie_migration_example
Create movie_migration_example.info file
name: "Movies Migration"
description: "Module to migrate content from JSON source"
package: "Custom"
core: 7.x
dependencies[] = migrate
dependencies[] = field
dependencies[] = file
dependencies[] = image
dependencies[] = number
dependencies[] = text
files[] = movies_migration.module
files[] = MoviesMigration.inc
Create movie_migration_example.module file
<?php
/**
* Implements hook_migrate_api()
*/
function movies_migration_migrate_api() {
$api = array(
   'api' => 2,
   'migrations' => array(
     'MoviesMigration' => array('class_name' => 'MoviesMigration'),
   ),
);
}

Now, we’ll create our JSON source migration class MoviesMigration.inc
<?php
/**
* @file
* Define a MoviesMigration Migration class for node migration.
*/
class MoviesMigration extends Migration {
....
}

Now, we’ll add unique ID map to our class using __construct. In my case, I have unique source ID in varchar.
<?php
/**
* @file
* Define a MoviesMigration Migration class for node migration.
*/
class MoviesMigration extends Migration {
/**
  * A constructor.
  */
public function __construct($arguments) {
   parent::__construct($arguments);
  
   // Map for the migration.
   $this->map = new MigrateSQLMap($this->machineName,
    array(
      'imdb_id' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'description' => 'Movie ID',
      ),
    ),
    MigrateDestinationNode::getKeySchema()
   );
}
}

Now add mapping:
<?php
/**
* @file
* Define a MoviesMigration Migration class for node migration.
*/
class MoviesMigration extends Migration {
/**
  * A constructor.
  */
public function __construct($arguments) {
   parent::__construct($arguments);
  
   // Map for the migration.
   $this->map = new MigrateSQLMap($this->machineName,
    array(
      'imdb_id' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'description' => 'Movie ID',
      ),
    ),
    MigrateDestinationNode::getKeySchema()
   );
   $source_url = http://www.example.com/data/json/movies.json
   $this->source = new MigrateSourceJSON($source_url, 'imdb_id', $this->fields());
   // Destination node type is movies.
   $this->destination = new MigrateDestinationNode('movies');
   // Map node's title field to the title in the json content.
   $this->addFieldMapping('title', 'title');
   // Map node's body field to the content in the json content.
   $this->addFieldMapping('body', 'plot');
   // Map node's field_id field to the id in the json content.
   $this->addFieldMapping('field_imdb_id', 'imdb_id');
   // Map node's field_poster to the poster in the json content.
   $this->addFieldMapping('field_poster', 'poster');
   // Map node's field_genre field to the genre in the json content.
   $this->addFieldMapping('field_genre', 'genre')
    ->separator(',');
   $this->addFieldMapping('field_genre:create_term')
    ->defaultValue(TRUE);
   // Hide comments.
   $this->addFieldMapping('comment', NULL)->defaultValue(COMMENT_NODE_CLOSED);
}
/**
  * Return the fields (this is cleaner than passing in the array
  *  in the MigrateSourceJSON class above)
  * @return array
  */
function fields() {
   return array(
     'title' => 'The title of the content',
     'plot' => 'The body of the content',
     'poster' => 'Image Source url associated with the content',
     'imdb_id' => 'IMDB ID associated with the content',
     'genre' => 'Genre associated with the content',
   );
}
}

That’s it!

Now, you just need to complete the following steps to import content using your migration class.

  • Go to admin/content/migrate/configure
  • Click on “Register statically defined classes” button to register our MoviesMigration class
  • Go to admin/content/migrate/groups/default (your newly added migration should be visible here)
  • Click Import button to start migration.


Conclusion
Using JSON API migration, you don’t need to worry about data structure as JSON already provides data in a structured way. Also, you don’t need to worry about SQL skills, which would be required in the case of database migration to pull data from the source database in a structured way, so that it can be migrated without errors or broken data. JSON migration also saves you from having to write a lot of code—you just need a source URL and you’re good to go.

Hurray!

If you have any questions, please feel free to comment.