This document provides a step-by-step guide for the complete workflow of bulk updating metadata across multiple datasets.
Step 1: JSON Templates Step 2: CSV Generation Step 3: Edit CSV
↓ ↓ ↓
[ZIP or JSON files] → [json_to_csv.py] → [metadata.csv]
(Edit in Excel)
↑ ↓
Step 8: Push Updates to Step 7: Review JSON Step 4: Convert
Dataverse Output Files Back to JSON
↑ ↓
└────────────────────────────────┬────────────────────┘
Step 5-6: Generate JSON
[csv_to_json.py]
You have two options:
Option A: Using existing JSON files
# If you have JSON files, place them in data/json_templates/
mkdir -p data/json_templates
# Copy your JSON files here
cp path/to/your/json/files/* data/json_templates/Option B: Using a ZIP file
# If you have a ZIP file with JSON files
unzip -d data/json_templates your_datasets.zipOption C: Create new JSON files Create JSON files following the template structure (see JSON Template Format section in README).
# List all JSON files
ls -la data/json_templates/
# Check structure of a JSON file
cat data/json_templates/your_file.json | python -m json.toolpython json_to_csv.py \
--input-dir ./data/json_templates \
--output-csv ./data/metadata.csvExpected output:
Processing: ./data/json_templates/climate_data_2024.json
Processing: ./data/json_templates/genomic_data_species_a.json
Processing: ./data/json_templates/survey_data_2024.json
Successfully converted 11 rows to ./data/metadata.csv
# View first 5 rows
head -5 data/metadata.csv
# Count total rows
wc -l data/metadata.csv
# View column headers
head -1 data/metadata.csv# Open with default application
open data/metadata.csv # macOS
xdg-open data/metadata.csv # Linux
start data/metadata.csv # WindowsOr use an online editor like Google Sheets.
For each row you want to update:
-
Review the current data
- Check
original_descriptioncolumn for context - Note the
file_labelto understand what file you're updating
- Check
-
Fill in
new_descriptioncolumnOriginal: "Temperature data" New: "Monthly average temperature data with quality control applied, covering 2023-2024 period for North America" -
Fill in
new_file_pathcolumn (if reorganizing)Original: "raw_data" New: "raw_data/v2" -
Update
statuscolumnpending- To be updatedno_changes- Skip this rowskip- Ignore entirely
-
Save the CSV file
Create a validation script to check CSV before proceeding:
#!/usr/bin/env python3
# validate_csv.py
import csv
with open('data/metadata.csv', 'r') as f:
reader = csv.DictReader(f)
for i, row in enumerate(reader, 1):
# Check for required fields
if not row['DOI']:
print(f"Row {i}: Missing DOI")
if not row['file_id']:
print(f"Row {i}: Missing file_id")
# Check for data in status field
if row['status'] not in ['pending', 'no_changes', 'skip', 'updated']:
print(f"Row {i}: Invalid status: {row['status']}")
print("Validation complete!")Run it:
python validate_csv.pypython csv_to_json.py \
--csv-file ./data/metadata.csv \
--output-dir ./data/json_outputExpected output:
✓ Created: ./data/json_output/doi_10_5061_dryad_example1.json
✓ Created: ./data/json_output/doi_10_5061_dryad_example2.json
✓ Created: ./data/json_output/doi_10_5061_dryad_example3.json
Successfully converted 3 JSON files to ./data/json_output
# Check JSON validity
python -c "import json; json.load(open('data/json_output/doi_10_5061_dryad_example1.json'))" && echo "Valid JSON"
# View generated file structure
cat data/json_output/doi_10_5061_dryad_example1.json | python -m json.tool
# Compare with original
diff data/json_templates/climate_data_2024.json data/json_output/doi_10_5061_dryad_example1.json# Set environment variables
export DATAVERSE_SERVER_URL="https://dataverse.example.org"
export DATAVERSE_API_TOKEN="your-api-token-here"
# Or add to shell profile for persistence
echo 'export DATAVERSE_SERVER_URL="https://dataverse.example.org"' >> ~/.bashrc
echo 'export DATAVERSE_API_TOKEN="your-api-token-here"' >> ~/.bashrc
source ~/.bashrcGetting your API token:
- Go to Dataverse instance Settings → Account
- Click "Create API Token"
- Copy and save securely (never commit to version control)
# Test if credentials are correct
python dataverse_api.py \
--csv-file ./data/metadata.csv \
--server-url "https://dataverse.example.org" \
--api-token "your-token"This runs in dry-run mode by default and shows what would be updated.
python dataverse_api.py \
--csv-file ./data/metadata.csvReview output:
============================================================
Dataset: doi:10.5061/dryad.example1
Files to update: 2
File ID: file_001
Label: temperature_data.csv
Description: Monthly average... → Updated monthly average...
✓ Updated
File ID: file_002
Label: precipitation_analysis.xlsx
Description: Precipitation patterns... → New analysis including...
✓ Updated
============================================================
DRY RUN: Would update 3 files
Use --no-dry-run to apply changes
# Apply the actual updates
python dataverse_api.py \
--csv-file ./data/metadata.csv \
--no-dry-runVerify changes in Dataverse:
- Go to each dataset in Dataverse web interface
- Check that file descriptions and paths have been updated
- Verify all files are still accessible
After successful push, update the CSV status column:
- Change
pendingtoupdated - Update
new_descriptionto blank (changes applied) - Save as
./data/metadata_final.csv
Update only one dataset instead of multiple:
# Extract single dataset from CSV
# (or create new CSV with single dataset)
python csv_to_json.py \
--csv-file ./data/single_dataset.csv \
--output-dir ./data/json_output
python dataverse_api.py \
--csv-file ./data/single_dataset.csvTrack multiple update batches:
# First batch
python dataverse_api.py --csv-file ./data/batch1.csv --no-dry-run
# Second batch
python dataverse_api.py --csv-file ./data/batch2.csv --no-dry-run
# Track in version control
git add data/batch*.csv
git commit -m "Dataverse metadata updates - batches 1 and 2"Create a cron job for regular updates:
# Add to crontab (monthly updates)
0 3 1 * * cd /path/to/project && python json_to_csv.py && \
python csv_to_json.py --csv-file ./data/metadata.csv && \
python dataverse_api.py --csv-file ./data/metadata.csv --no-dry-runSolution:
# Check if JSON files have correct structure
python -c "
import json
from utils import load_json_file
json_file = 'data/json_templates/your_file.json'
data = load_json_file(json_file)
print(f'DOI: {data.get(\"datasetPersistentId\")}')
print(f'Files: {len(data.get(\"data\", []))}')
"Solution:
# Validate CSV format
python -c "
import csv
with open('data/metadata.csv', 'r') as f:
reader = csv.DictReader(f)
print(f'Columns: {reader.fieldnames}')
for i, row in enumerate(reader, 1):
if i <= 3:
print(f'Row {i}: {row}')
"Solution:
# Check what data is in each CSV row
python -c "
from utils import load_csv_file
rows = load_csv_file('data/metadata.csv')
for row in rows:
if row['DOI']:
print(f'{row[\"DOI\"]}: {len([v for v in row.values() if v])} fields filled')
"Solution:
# Check file IDs are valid
python -c "
from utils import load_csv_file
rows = load_csv_file('data/metadata.csv')
for row in rows[:3]:
print(f'File ID: {row.get(\"file_id\")}, Label: {row.get(\"file_label\")}')
"-
Backup first: Keep originals in git
git add data/json_templates/* git commit -m "Backup original JSON files"
-
Work in small batches: Update 5-10 datasets at a time
-
Review changes visually: Always check Dataverse web interface after updates
-
Keep audit trail: Use git to track CSV changes
git diff data/metadata.csv git add data/metadata.csv git commit -m "Updated descriptions for climate and survey datasets" -
Document changes: Add notes in git commit messages
git commit -m "Updated 8 file descriptions for improved clarity - Climate data: Added quality control info - Survey data: Added year range info - Genomic data: Added platform specification"
If something goes wrong:
# Restore original JSON files
cp data/json_templates/* data/json_output/
# Revert CSV changes
git checkout data/metadata.csv
# Check git history
git log --oneline data/metadata.csv
# Restore previous version
git checkout HEAD~1 -- data/metadata.csv