HoldingsCsvTransformer#
Transform delimited (CSV/TSV) data into FOLIO Holdings records. Use this when your holdings data comes from item-level exports or systems without MFHD support.
When to Use This Task#
Migrating from systems that export item-level data (Sierra, III, etc.)
Creating holdings records from item data when no separate holdings exist
Merging multiple items into consolidated holdings records
Combining with previously generated MFHD-based holdings
Configuration#
{
"name": "transform_csv_holdings",
"migrationTaskType": "HoldingsCsvTransformer",
"holdingsMapFileName": "holdings_mapping.json",
"locationMapFileName": "locations.tsv",
"defaultCallNumberTypeName": "Library of Congress classification",
"fallbackHoldingsTypeId": "03c9c400-b9e3-4a07-ac0e-05ab470233ed",
"holdingsMergeCriteria": ["instanceId", "permanentLocationId", "callNumber"],
"files": [
{
"file_name": "items.tsv"
}
]
}
Parameters#
Parameter |
Type |
Required |
Description |
|---|---|---|---|
|
string |
Yes |
The name of this task. |
|
string |
Yes |
Must be |
|
string |
Yes |
JSON mapping file for holdings fields |
|
string |
Yes |
TSV file mapping legacy locations to FOLIO codes |
|
string |
Yes |
FOLIO call number type name for fallback |
|
string |
Yes |
UUID of fallback holdings type |
|
array |
No |
Fields used to group items into holdings. Default: |
|
string |
No |
TSV file mapping call number types |
|
string |
No |
TSV file mapping holdings types |
|
string |
No |
TSV file mapping statistical codes |
|
string |
No |
UUID of holdings type for boundwith holdings (enables automatic boundwith handling) |
|
array |
No |
List of previous holdings result files to avoid duplicates |
|
array |
Yes |
List of source data files to process |
Source Data Requirements#
Location: Place CSV/TSV files in
iterations/<iteration>/source_data/items/Format: Tab-separated (TSV) or comma-separated (CSV) with header row
Prerequisite: Run BibsTransformer first to create
instance_id_map
Holdings Mapping File#
Create a JSON mapping file in mapping_files/:
{
"data": [
{
"folio_field": "legacyIdentifier",
"legacy_field": "ITEM_ID",
"description": "Legacy identifier for deterministic UUID"
},
{
"folio_field": "instanceId",
"legacy_field": "BIB_ID",
"description": "Links to the parent instance"
},
{
"folio_field": "permanentLocationId",
"legacy_field": "LOCATION_CODE",
"description": "Mapped via locationMapFileName"
},
{
"folio_field": "callNumber",
"legacy_field": "CALL_NUMBER",
"description": "Call number for the holdings"
},
{
"folio_field": "callNumberTypeId",
"legacy_field": "CN_TYPE",
"description": "Mapped via callNumberTypeMapFileName"
}
]
}
Important
The legacyIdentifier field is required and must map to a unique value in your source data. This value is used to generate deterministic UUIDs.
Reference Data Mapping Files#
Reference data mapping files connect values from your legacy data to FOLIO reference data. See Reference Data Mapping for detailed documentation on how these files work.
Mapping File |
FOLIO Column |
Maps To |
|---|---|---|
|
|
Location code |
|
|
Call number type name |
Holdings Merge Criteria#
The holdingsMergeCriteria parameter determines how multiple rows in the source data are consolidated into single holdings records.
Example: With ["instanceId", "permanentLocationId", "callNumber"]:
Items with the same bib ID, location, and call number → one holdings record
Items with different locations → separate holdings records
Common configurations:
Strategy |
Merge Criteria |
Result |
|---|---|---|
One holdings per item |
|
1:1 item to holdings |
Group by location |
|
Holdings per location |
Group by location + call number |
|
Holdings per location + call number |
Output Files#
Files are created in iterations/<iteration>/results/:
File |
Description |
|---|---|
|
FOLIO Holdings records |
|
Legacy ID to FOLIO UUID mapping (used by ItemsTransformer) |
|
Extra data including boundwith parts (when applicable) |
Examples#
Basic Holdings from Items#
{
"name": "transform_csv_holdings",
"migrationTaskType": "HoldingsCsvTransformer",
"holdingsMapFileName": "holdings_mapping.json",
"locationMapFileName": "locations.tsv",
"defaultCallNumberTypeName": "Library of Congress classification",
"fallbackHoldingsTypeId": "03c9c400-b9e3-4a07-ac0e-05ab470233ed",
"files": [
{
"file_name": "items.tsv"
}
]
}
Combining with MFHD Holdings#
When you have both MFHD-derived holdings and need additional holdings from items:
{
"name": "transform_csv_holdings",
"migrationTaskType": "HoldingsCsvTransformer",
"holdingsMapFileName": "holdings_mapping.json",
"locationMapFileName": "locations.tsv",
"defaultCallNumberTypeName": "Library of Congress classification",
"fallbackHoldingsTypeId": "03c9c400-b9e3-4a07-ac0e-05ab470233ed",
"previouslyGeneratedHoldingsFiles": [
"folio_holdings_transform_mfhd.json"
],
"files": [
{
"file_name": "items_without_mfhd.tsv"
}
]
}
With Statistical Codes#
{
"name": "transform_csv_holdings",
"migrationTaskType": "HoldingsCsvTransformer",
"holdingsMapFileName": "holdings_mapping.json",
"locationMapFileName": "locations.tsv",
"defaultCallNumberTypeName": "Library of Congress classification",
"fallbackHoldingsTypeId": "03c9c400-b9e3-4a07-ac0e-05ab470233ed",
"statisticalCodeMapFileName": "stat_codes.tsv",
"files": [
{
"file_name": "items.tsv",
"statistical_code": "migrated"
}
]
}
Boundwith Handling#
The HoldingsCsvTransformer handles boundwith relationships automatically when an item maps to multiple instance IDs (i.e., the source data row resolves to more than one bib). You may see these referred to as “Sierra-style boundwiths” or “Millenium-style boundwiths”. This differs from the MFHD-based approach used by HoldingsMarcTransformer, which requires a separate boundwith relationship file.
How It Works#
When a source data row maps to multiple instances:
A primary holdings record is created for the first instance.
Additional holdings records are generated for each subsequent instance, with their
holdingsTypeIdset toholdingsTypeUuidForBoundwiths.A
boundwithPartrecord is written to the extradata file linking the item to each holdings record.Boundwith holdings are excluded from the normal
holdingsMergeCriteriamerge process. Instead, they are de-duplicated using their own composite key (instance ID + location + call number + the full set of bound instance IDs). If a subsequent row produces the same boundwith key, it is merged into the existing boundwith holdings record rather than creating a duplicate.
Configuration#
To enable boundwith handling, set the holdingsTypeUuidForBoundwiths parameter to the UUID of the appropriate holdings type from your FOLIO tenant (found under Settings → Inventory → Holdings types):
{
"name": "transform_csv_holdings",
"migrationTaskType": "HoldingsCsvTransformer",
"holdingsMapFileName": "holdings_mapping.json",
"locationMapFileName": "locations.tsv",
"defaultCallNumberTypeName": "Library of Congress classification",
"fallbackHoldingsTypeId": "03c9c400-b9e3-4a07-ac0e-05ab470233ed",
"holdingsTypeUuidForBoundwiths": "1b6c62cf-034c-4972-ac80-fa595a9bfbde",
"files": [
{
"file_name": "items.tsv"
}
]
}
Note
No boundwithFlavor or boundwithRelationshipFilePath is needed for the CSV transformer. Boundwith detection is automatic based on multiple instance IDs in the source data.
Running the Task#
folio-migration-tools mapping_files/config.json transform_csv_holdings --base_folder ./
Next Steps#
Transform Items: Use ItemsTransformer on the same source files
Post Holdings: Use InventoryBatchPoster or BatchPoster
See Also#
Mapping File Based Mapping - Mapping file syntax
HoldingsMarcTransformer - Alternative for MFHD records
ItemsTransformer - Transforming items from the same data