Reference

Mapping Strategy

By default, importOK matches fields to columns in the uploaded file using the Levenshtein distance between field names and headers.

importOK takes into consideration several factors to create the most accurate mapping possible: the field name itself, the field label (display name), any defined aliases for the field, and applies fuzzy string matching using Levenshtein distance to handle minor variations in naming conventions. This multi-layered approach ensures that fields are matched even when column headers don't exactly match the expected field names, accounting for common variations like underscores vs spaces, abbreviations, and slight misspellings.

If the Power Pack is enabled and a valid license key is provided, importOK switches to the AI Mapping Strategy, which uses AI to understand context and variations in naming. This allows it to map fields more accurately when headers are inconsistent or less obvious, compared to the similarity-based matching used by default.

While this approach is quite efficient, you might want to apply your own mapping strategy. For example, you could perform a heuristic analysis and try to match the fields to the headers based on the uploaded data itself. Alternatively, you could connect to your API and do the mapping on the server side.

1{
2 mapper: function(context) {
3 // Access all data through the context object
4 const { fields, headers, records, meta } = context;
5 // ... your mapping logic
6 }
7}

The mapper can be an asynchronous or synchronous function that receives a context object with all the necessary data and returns the best possible mapping.

Parameters

The mapper receives a context object with the following properties:

context.fields

Description An object containing all field definitions from your configuration. Keys are field names, values are field definitions with labels, transformers, validators, etc.
Type { [key: string]: ImportField }

context.headers

Description An array including all the header names included in the uploaded file
Type string[]

context.records

Description An array of preview records (first few rows) from the uploaded file. These are read-only and used for analysis purposes only.
Type ImportRecord[]

context.meta

Description Metadata about the uploaded file including size, name, type, and whether it has a header row
Type { importok: { fileSize: number; fileName: string; fileType: string; withHeader: boolean }, [key: string]: any }

Mapping

The mapper should return an object where the keys are the field names and the values are the corresponding header names. If a field cannot be mapped, the value must be null.

1// Example return value
2{
3 "firstName": "First Name", // Maps field 'firstName' to header 'First Name'
4 "lastName": "Last Name", // Maps field 'lastName' to header 'Last Name'
5 "email": "Email Address", // Maps field 'email' to header 'Email Address'
6 "age": null // Field 'age' couldn't be mapped to any header
7}

Examples

Here is an example of a custom mapping strategy that maps headers to fields using an exact match approach:

1{
2 mapper: (context) => {
3 const { fields, headers, records, meta } = context;
4 
5 // Skip mapping if file has no header row
6 if (!meta.importok.withHeader) {
7 return {};
8 }
9 
10 const mapping = {};
11 const fieldNames = Object.keys(fields);
12 
13 fieldNames.forEach((fieldName) => {
14 const field = fields[fieldName];
15 
16 // Try exact match first
17 let matchedHeader = headers.find(header =>
18 header.toLowerCase() === fieldName.toLowerCase()
19 );
20 
21 // Try matching against field label if no exact match
22 if (!matchedHeader && field.label) {
23 matchedHeader = headers.find(header =>
24 header.toLowerCase() === field.label.toLowerCase()
25 );
26 }
27 
28 mapping[fieldName] = matchedHeader || null;
29 });
30 
31 return mapping;
32 }
33}

Extending Built-in Mappers

Instead of creating a completely custom mapping strategy, you can create a wrapper around the built-in mapping strategies to add your own logic while still benefiting from the proven algorithms. This approach allows you to extend the default behavior with domain-specific rules or post-processing steps.

Here's how to create a wrapper that enhances the default mapper with custom logic:

1import { LevenshteinMappingStrategyWithContext } from '@importok/javascript';
2 
3{
4 mapper: async (context) => {
5 // First, get the default mapping
6 const defaultMapping = await LevenshteinMappingStrategyWithContext(context);
7 
8 // Apply your custom enhancements
9 const enhancedMapping = { ...defaultMapping };
10 
11 // Example: Apply custom rules for specific fields
12 if (context.headers.includes('Customer Name')) {
13 enhancedMapping.customerName = 'Customer Name';
14 }
15 
16 // Example: Override mapping for email fields
17 const emailHeader = context.headers.find(h =>
18 h.toLowerCase().includes('email') || h.toLowerCase().includes('mail')
19 );
20 if (emailHeader && context.fields.email) {
21 enhancedMapping.email = emailHeader;
22 }
23 
24 return enhancedMapping;
25 }
26}

Backwards Compatibility

For backwards compatibility, mappers using the parameter-based signature (fields, headers, records, hasNumericColumns) are still supported but deprecated and will be removed in v3.0.

Start typing to search documentation and articles...

⌘K or Ctrl+K to open search

No results found for ""

Try different keywords or check your spelling.

Use ↑ ↓ arrow keys to navigate and Enter to select