Feishu Goods Mapping Table Sync to MySQL: A Single-Strategy Tutorial
What This Strategy Solves
In one of our retail projects, the operations team maintained a goods mapping table in Feishu Sheets, recording external product codes, names, and specifications alongside our internal product codes and names. Finance and supply chain data lived in MySQL, and downstream order, invoice, and pricing workflows all depended on this mapping. When the two sides drifted apart, orders stalled, invoices failed, and inventory no longer reconciled.
This strategy has a single goal: pull the Feishu mapping table on a schedule and write it into MySQL so that every downstream system uses one consistent set of internal product codes. It looks simple, but a poorly designed mapping causes silent divergence after three months — a classic pitfall.
Data Flow and Field Mapping
The flow is Feishu Sheets (source) → Qeasy (middleware) → MySQL (target). The source uses the Feishu open platform Sheets API, and the target uses MySQL batch execution (batchexecute).
Key field mapping:
| Business Meaning | Feishu Source Field | MySQL Target Field | Notes |
|---|---|---|---|
| Primary key | id | id | Used by both incremental and full sync |
| Brand | 品牌 | 品牌 | Direct mapping |
| Product name | 品名 | 品名 | Direct mapping |
| Specification | 规格 | 规格 | Direct mapping |
| Internal product code | 我司商品编码 | 我司商品编码 | Core of the mapping table |
| Internal product name | 我司商品名称 | 我司商品名称 | Core of the mapping table |
The source is fetched in ascending id order; the target writes by id with idCheck enabled so primary-key conflicts surface immediately.
How to Configure in Qeasy
We built this pipeline on the Qeasy data integration platform. Key configuration points:
- Source platform: choose Feishu, configure appId/appSecret (omitted here per data-handling rules), authorize the tenant space, and put the target spreadsheetToken into the path parameter slot.
- Source API: use
GET /open-apis/sheets/v2/spreadsheets/:spreadsheetToken/values/:range, setvalueRenderOptiontoToStringanddateTimeRenderOptiontoFormattedStringso dates and numbers are not corrupted during serialization. - Target platform: a MySQL data source. Use
batchexecute, parameterize the INSERT SQL with{{field}}placeholders that reference source data. - Field mapping: in the mapping node, align Feishu columns with MySQL fields. Two patterns are common across our customers — keep mappings in a centralized mapping-config table so new columns are added by config change rather than strategy edits; or use a phased "header-then-body" rollout that stabilizes the header fields first and only then layers in the body.
- Auto-fill response: enable
autoFillResponseon the target side so the platform echoes back the affected fields for easier troubleshooting.
Implementation Steps
Implementation follows three phases: incremental starting point → full trigger → schedule cadence.
- Incremental start: use the maximum
idin the current Feishu mapping table as the starting point so the first run does not replay history. - Full trigger: on go-live, manually trigger a full run to backfill historical mappings; validate mapping and charset in a test database first.
- Schedule cadence: the source crontab is
0 1 * * *and the target is30 1 * * *, leaving a 30-minute buffer for network jitter and mapping exceptions. A common "incremental + full dual-track" pattern we have seen works well: run incremental daily, trigger a manual full reconciliation once a month to guarantee both sides match exactly.
Lessons Learned
- Date and number formats: if Feishu returns date cells as timestamps by default, MySQL will treat them as dates in 1970. The safe approach is
valueRenderOption=ToStringanddateTimeRenderOption=FormattedString, landing strings in VARCHAR and letting the MySQL view layer handle type conversion. - Centralized mapping management: a common mistake is to hard-code mappings into the SQL template, forcing a strategy edit whenever a column is added. Keep mappings in a config table so operations can maintain them directly.
- Do not disable
idCheckcarelessly: this strategy sets source idCheck off and target idCheck on. Turning off target idCheck lets primary-key conflicts fail silently, which is extremely painful to debug. - Crontab buffering: running source and target at the same sharp hour collides with Feishu rate limits and MySQL connection pool exhaustion. A 30-minute offset is the safe value validated across multiple customer environments.
When to Use and When Not to
This pattern fits mapping-table / master-data scenarios with under tens of thousands of rows, scheduled daily or hourly, with no real-time requirement. It is not suitable for high-concurrency real-time ordering paths, source structures that change frequently, or complex bidirectional sync; those scenarios call for event-driven architectures or dedicated reconciliation services.