Mapping input fields to output fields

Many common geoprocessing tasks require detailed control over the fields in the output datasets, such as the following:

  • Merging many datasets into a new or existing dataset when the attributes or fields do not match
  • Exporting an input dataset that has editor tracking fields that you want to preserve

For these use cases, use a field map parameter to define the relationships between fields of different names and types. Field mapping can also be accomplished in a Python script.

FieldMap

The FieldMap object provides a field definition and a list of input fields from a set of tables or feature classes that provide its values.

The properties of the FieldMap object include the start and end position of an input text value, so an output value can be created using a slice of an input value. If a FieldMap object contains multiple input fields from the same table or feature class, each record's values are merged using the mergeRule property. This is a convenient way to join values, such as a street name that is held in one field and a street type that is held in another, for example, Eureka and Street. The joinDelimiter property of the FieldMap object is used when Join is specified as the mergeRule value. Any set of characters, such as a space, can be used as a delimiter. In the example above, this would create a value of Eureka Street.

FieldMappings

The FieldMappings object is a collection of FieldMap objects, and it is used as the parameter value for tools that perform field mapping, such as Merge. The easiest way to work with these objects is to first create a FieldMappings object, then initialize its FieldMap objects by adding the input feature classes or tables that are to be combined. Once all inputs are provided, the FieldMappings object will contain one FieldMap object, or output field, for each unique field name from all the inputs. You can modify this list by adding new fields, altering the properties or contents of an output field, or removing unwanted output fields.

Examples

In the following example, a number of feature classes containing U.S. census data will be merged to form a new feature class. One of the input attributes that is in all the inputs is a numeric field, STFID. This 15-digit value is a unique identifier for all census blocks in the United States. The value can be divided into four components. The first two digits provide the state code, the next three indicate the county, the following six identify the census tract, and the last four identify the census block. The value 360899912001006 represents the census block (1006) containing the State University of New York at Potsdam in upstate New York (36), within census tract 991200 of the county of St. Lawrence (089). The script sample will merge these feature classes and create two fields, TRACTID and BLOCKID, because the input data only has the STFID attribute. To do this, the FieldMappings object is initialized using the addTable method to enter each input. Then the default FieldMappings object is modified by creating two FieldMap objects, populating their properties, and adding them to the FieldMappings object.

import arcpy

arcpy.env.workspace = "C:/Data/CityBlocks.gdb"
outfc = "C:/Data/CityBlocks.gdb/AllBlocks"

# Each of the input Feature classes has an STFID, which is the combination of 
# the Tract ID and Block ID for each block. Separate these values from this 
# field into two new fields, TRACTID and BLOCKID.

# Create a fieldmappings and two new fieldmaps.
fieldmappings = arcpy.FieldMappings()
fldmap_TRACTID = arcpy.FieldMap()
fldmap_BLOCKID = arcpy.FieldMap()

# List all the feature classes in the workspace that start with 'block' in 
# their name and are of polygon feature type.
fcs = arcpy.ListFeatureClasses("block*", "Polygon")

# Create a value table that will hold the input feature classes to Merge
vTab = arcpy.ValueTable()
for fc in fcs:
    # Adding a table is the fastest way to load all the fields from the input 
    # into fieldmaps held by the fieldmappings object.
    fieldmappings.addTable(fc)

    # This example also creates two fieldmaps by 'chopping up' an input field. 
    # Feed the chopped field into the new fieldmaps.
    fldmap_TRACTID.addInputField(fc, "STFID")
    fldmap_BLOCKID.addInputField(fc, "STFID")

    # Populate the input value table with feature classes
    vTab.addRow(fc)

# Set the starting and ending position of the fields going into the TractID 
# fieldmap. This is the location in the STFID field where the TractID falls.
for x in range(0, fldmap_TRACTID.inputFieldCount):
    fldmap_TRACTID.setStartTextPosition(x, 5)
    fldmap_TRACTID.setEndTextPosition(x, 10)

# Set the Name of the Field output from this field map.
fld_TRACTID = fldmap_TRACTID.outputField
fld_TRACTID.name = "TRACTID"
fldmap_TRACTID.outputField = fld_TRACTID

# Set the starting and ending position of the fields going into the BlockID 
# fieldmap. This is the location in the STFID field where the blockID falls.
for x in range(0, fldmap_BLOCKID.inputFieldCount):
    fldmap_BLOCKID.setStartTextPosition(x, 11)
    fldmap_BLOCKID.setEndTextPosition(x, 16)

# Set the Name of the Field output from this field map.
fld_BLOCKID = fldmap_BLOCKID.outputField
fld_BLOCKID.name = "BLOCKID"
fldmap_BLOCKID.outputField = fld_BLOCKID

# Add the custom fieldmaps into the fieldmappings object.
fieldmappings.addFieldMap(fldmap_TRACTID)
fieldmappings.addFieldMap(fldmap_BLOCKID)

# Run the Merge tool.
arcpy.management.Merge(vTab, outfc, fieldmappings)

The next example shows how to modify a FieldMap object after it has been created using the addTable method of the FieldMappings object. This is important when the inputs have fields with different names but logically contain the same values.

import arcpy

outfc = "C:/data/CityData.gdb/AllBlocks"

# Want to merge these two feature classes together. Have a field that has the 
# same content but the names are slightly different: Blocks1 has TRACT2000 
# and Blocks2 TRACTCODE. Name the output the same as Blocks1.
fc1 = "C:/data/CityData.gdb/Blocks1"
fc2 = "C:/data/CityData.gdb/Blocks2"

# Create a new fieldmappings and add the two input feature classes.
fieldmappings = arcpy.FieldMappings()
fieldmappings.addTable(fc1)
fieldmappings.addTable(fc2)

# First get the TRACT2000 fieldmap. Then add the TRACTCODE field from Blocks2 
# as an input field. Then replace the fieldmap within the fieldmappings object.
fieldmap = fieldmappings.getFieldMap(fieldmappings.findFieldMapIndex("TRACT2000"))
fieldmap.addInputField(fc2, "TRACTCODE")
fieldmappings.replaceFieldMap(fieldmappings.findFieldMapIndex("TRACT2000"), fieldmap)

# Remove the TRACTCODE fieldmap.
fieldmappings.removeFieldMap(fieldmappings.findFieldMapIndex("TRACTCODE"))

# Run the Merge tool.
arcpy.management.Merge([fc1, fc2], outfc, fieldmappings)

The next example shows how to preserve editor tracking fields in a Python script. When using the Export Features tool in the Geoprocessing pane or in ModelBuilder, tracking fields will automatically be listed in the Field Map parameter. However, when using the addTable method of the FieldMappings object, the edit tracking fields must be explicitly added to be included.

import arcpy

fc = "DBO.Points"
desc = arcpy.Describe(fc)

# Create a new fieldmappings and add the input feature class.
fieldmappings = arcpy.FieldMappings()
fieldmappings.addTable(fc)

if desc.editorTrackingEnabled:
    tracking_fields = [
        desc.creatorFieldName, 
        desc.createdAtFieldName, 
        desc.editorFieldName, 
        desc.editedAtFieldName
    ]

    for tf in tracking_fields:
        # Create a fieldmap for each tracking field and add to the fieldmappings object.
        fieldmap = arcpy.FieldMap()
        fieldmap.addInputField(fc, tf)
        fieldmappings.addFieldMap(fieldmap)

# Run the tool
arcpy.conversion.ExportFeatures(fc, "memory/Output", field_mapping=fieldmappings)