Map content to new structure

Jan Cerman
14 minutes
0% complete
Define how to map your exported content to your new content model. To make the mapping easier, use the Kontent.ai Migration toolkit to ensure your content items and assets are correctly structured and referenced in your new project.

Mapping on paper

Before you start writing the mapping logic in code, we recommend you first define the mapping visually. You can do this on digital or analog paper. Visual mapping lets you and other stakeholders see how your existing content fits within the new content model. You’ll see which parts fit and which don’t. If a part doesn’t fit, you can adjust the content model or discard that part if it’s not needed. This lets you find possible gaps in your content model early on.

Example mapping

Check the following diagram to see how an existing structure used for blog posts in one system can be mapped to a content model in Kontent.ai. The Kontent.ai content model in the example is based on the Article content modeling accelerator. Notice that the Blog post’s fields don’t always map one-to-one to the Article’s elements; sometimes, you need to transform the existing content to another format. Text fields can usually be mapped 1:1. For anything more complex, there is often a transformation involved.

Mapping in code

Once you’ve verified everything on paper, you can move to the real thing. To simplify the mapping in code, use the Kontent.ai Migration toolkit. The toolkit handles requests to Management API for you and makes the content migration easier. For example, the toolkit checks for existing assets and content items to ensure they’re referenced correctly.

Install the Migration toolkit

To get started, create a Node.js app and install the Migration toolkit by running the following command in the terminal.
  • Shell
# Add the Migration toolkit to your app
npm i @kontent-ai/migration-toolkit --save-dev

Migration toolkit 101

To migrate your exported content to a Kontent.ai project with the Migration toolkit, you need to:
  1. Map your textual and structured content to the MigrationItem objects.
  2. Map your binary files to the MigrationAsset objects.
  3. Import the mapped content from the MigrationItem and MigrationAsset objects to your Kontent.ai project.
  • TypeScript
import {
  MigrationAsset,
  MigrationItem,
  importAsync,
} from "@kontent-ai/migration-toolkit";

// 1. Map the exported content to MigrationItems
const migrationItems: MigrationItem[] = [];
// 2. Map exported files to MigrationAssets
const migrationAssets: MigrationAsset[] = [];
// 3. Import the mapped data into a Kontent.ai project
await importAsync({
  data: {
    assets: migrationAssets,
    items: migrationItems,
  },
  environmentId: "KONTENT_AI_ENVIRONMENT_ID",
  apiKey: "MANAGEMENT_API_KEY",
});
Let’s now see how to map content items and assets.

Map exported content to content items

Kontent.ai stores content in content items. Depending on the number of languages in your project, each content item has one or more content item variants. The Migration toolkit’s MigrationItem represents a single localized variant of a content item. This includes the variant’s metadata and elements. The specific elements depend on the content item’s content type. With each MigrationItem, you can choose to specify content for the content item variant’s latest version, published version, or both.
  • TypeScript
import { MigrationItem } from "@kontent-ai/migration-toolkit";

// MigrationItem defines a localized variant of a content item
const migrationItem: MigrationItem = {
  // Variant's metadata
  system: {
    // Name the content item. Item name is shared for all variants.
    name: "My content item",
    // Generate a unique content item codename
    codename: "my_content_item",
    // Assign the item to a collection
    collection: { codename: "default" },
    // Specify the variant's language
    language: { codename: "en_us" },
    // Specify the content type
    type: { codename: "article" },
    // Assign the item to a workflow
    workflow: { codename: "default" },
  },
  versions: [
    {
      // Put the variant in a specific workflow step
      workflow_step: { codename: "draft" },
      elements: {
        // Variant's content
        // For each element specified by the item's content type, add properties named using element codenames.
        // Example: element_codename: elementsBuilder.textElement({ value: 'plaintext' }),
      },
    },
  ],
};
The following example shows how you can map content to a MigrationItem. We recommend using strongly typed models for the MigrationItem objects.
  • TypeScript
import {
  MigrationElementModels,
  MigrationItem,
  MigrationItemSystem,
  elementsBuilder,
} from "@kontent-ai/migration-toolkit";

// We recommend you define the structure of your Kontent.ai content type
type LanguageCodenames = "default" | "en";
type CollectionCodenames = "default" | "global";
type WorkflowCodenames = "default" | "custom";
type WorkflowStepCodenames = "published" | "archived" | "draft";
type ContentTypeCodenames = "movie" | "actor";
type System<Codename extends ContentTypeCodenames> = MigrationItemSystem<
  Codename,
  LanguageCodenames,
  CollectionCodenames,
  WorkflowCodenames
>;

type MovieItem = MigrationItem<
  // Defines the elements in the 'Movie' content type defined in Kontent.ai
  {
    title: MigrationElementModels.TextElement;
    plot: MigrationElementModels.RichTextElement;
    length: MigrationElementModels.NumberElement;
    category: MigrationElementModels.MultipleChoiceElement;
    poster: MigrationElementModels.AssetElement;
    stars: MigrationElementModels.LinkedItemsElement;
    seoname: MigrationElementModels.UrlSlugElement;
    released: MigrationElementModels.DateTimeElement;
    releasecategory: MigrationElementModels.TaxonomyElement;
  },
  System<"movie">,
  WorkflowStepCodenames
>;

const movie: MovieItem = {
  system: {
    name: "Warrior",
    // Ensure a unique codename. Check https://kontent.ai/learn/rules-for-codenames
    codename: "warrior",
    collection: { codename: "default" },
    language: { codename: "default" },
    type: { codename: "movie" },
    workflow: { codename: "default" },
  },
  // Specify up to 2 versions of the variant - latest and published.
  // The latest version can be in any workflow step.
  versions: [
    {
      workflow_step: {
        // You can publish the variant during the import, or use any other workflow step
        codename: "published",
      },
      elements: {
        title: elementsBuilder.textElement({ value: "Warrior" }),
        length: elementsBuilder.numberElement({ value: 140 }),
        category: elementsBuilder.multipleChoiceElement({
          value: [
            {
              codename: "drama",
            },
            {
              codename: "action",
            },
          ],
        }),
        poster: elementsBuilder.assetElement({
          value: [
            {
              codename: "warrior_teaser",
            },
          ],
        }),
        plot: elementsBuilder.richTextElement({
          // Check allowed HTML elements in rich text value at https://kontent.ai/learn/rich-text-in-mapi
          value: `<h1>Warrior</h1><p>...</p>`,
          components: [],
        }),
        releasecategory: elementsBuilder.taxonomyElement({
          value: [
            {
              codename: "global_release",
            },
          ],
        }),
        released: elementsBuilder.dateTimeElement({
          value: "2011-09-09T00:00:00Z",
        }),
        seoname: elementsBuilder.urlSlugElement({
          // The value is empty because it's autogenerated based on a dependent text element
          mode: "autogenerated",
          value: "",
        }),
        stars: elementsBuilder.linkedItemsElement({
          value: [
            {
              codename: "tom_hardy",
            },
          ],
        }),
      },
    },
  ],
};

const migrationItems: MigrationItem[] = [movie];

Parse rich text content

Plan for any necessary parsing of your existing rich text content to map it to the HTML5 rich text format supported by Kontent.ai’s Management API. Remember that the rich text editor in Kontent.ai doesn’t support custom visual formatting, such as setting text color or font size, for a reason. If your existing rich text content contains visual formatting, you need to decide whether to remove it or transform it into structured content. We recommend removing such custom formatting in most cases. Instead, let your web app or mobile app define how the content should be displayed. It will also mean your content creators can focus on the content instead of the formatting or visual options.

Map binary files to assets

The Migration toolkit’s MigrationAsset represents a single asset. You can reference assets by codenames in multiple MigrationItem objects. Every asset can specify localized asset descriptions for use as alt text.
  • TypeScript
import { MigrationAsset } from "@kontent-ai/migration-toolkit";
import { readFileSync } from "fs"; // Only if using local data

const coverAsset: MigrationAsset = {
  // You can read the data from anywhere, not just from the filesystem
  binary_data: readFileSync("./movies/posters/warrior.jpg"),
  // Ensure a unique asset codename. Check https://kontent.ai/learn/rules-for-codenames
  // This codename is used to reference the asset in the MigrationItem object
  codename: "warrior_teaser",
  // Name the binary file linked to the asset
  filename: "warrior_teaser.jpg",
  // Name the asset
  title: "Warrior cover",
  // (Optional) Asign the asset to a collection
  collection: {
    codename: "default",
  },
  // (Optional) Specify localized asset descriptions
  descriptions: [
    {
      language: {
        codename: "default",
      },
      description: "Poster for Warrior movie",
    },
  ],
};

const migrationAssets: MigrationAsset[] = [coverAsset];

Putting it together

Now that you know how to map your content and binary files to the migration objects, create mapping logic for your existing types of content.Once you have all the content mapped, you can start importing it to your project.
Sign in with your Kontent.ai credentials or sign up for free to unlock the full lesson, track your progress, and access exclusive expert insights and tips!