如何从两个长度不同的对象数组生成CategoryItems关联数组?
GraphQL CSV导入:生成分类-条目关联数组并插入
我知道这类话题已经讨论过很多次,但针对我的具体场景还是有疑问。我在GraphQL resolver中处理CSV导入数据,需要完成三次数据库插入操作。
原始输入数据格式
[{ name: 'Item 1', price: 0, quantity: 1, url: null, user_id: 1, category_name: 'Category 1', qty: null }, // ... 其他原始数据 ]
格式化后的数组
items数组
[{ id: 677, name: 'Item 1', price: 0, quantity: 1, url: null, user_id: 1, created_at: '2022-07-28T18:00:22.810136+00:00', updated_at: '2022-07-28T18:00:22.810136+00:00', }, // ... 其他条目 ]
categories数组
[{ id: 148, name: 'Category 1', list_id: 2, updated_at: '2022-07-28T18:00:23.09351+00:00', created_at: '2022-07-28T18:00:23.09351+00:00', }, // ... 其他分类 ]
期望的CategoryItems关联数组
[{ category_id: 148, item_id: 677, position: 1 }, { category_id: 148, item_id: 678, position: 2 }, { category_id: 149, item_id: 679, position: 1 }, ]
完整Resolver代码(已补全关联数组生成逻辑)
import { Context } from '@/context'; import { CsvImportInput, CsvImportResponse } from '@/generated/types'; import { genericError } from '@/helpers/errors'; import { getUserId } from '@/helpers/utils'; import formatCsv from '@/helpers/formatCsv'; import { getUniqueListBy } from '@/helpers/functions'; import supabase from '@/lib/supabase'; const csvImport = async (_parent: any, { input }: { input: CsvImportInput }, context: Context): Promise<CsvImportResponse> => { const userId = getUserId(context.token); if (!userId) { return { success: false, ...genericError({ message: 'Must supply user id', path: 'Csv import resolver: try' }), }; } const { data, list_id } = input; try { const formattedData = formatCsv(data, userId); // bulk insert items const { data: bulkInsertData, error: bulkInsertError } = await supabase .from('items') .insert(formattedData); console.log({ bulkInsertData }); console.log({ bulkInsertError }); if (!bulkInsertData || bulkInsertError) { return { success: false, ...genericError({ message: 'Error importing items', path: 'Csv import resolver: try' }), }; } // if not attaching to specific list if (!list_id) { return { success: true, errors: null, }; } else { // create categories const newCategories = data.map(item => ({ name: item.category_name, list_id })); const uniqueCategories = getUniqueListBy(newCategories, 'name'); console.log('uniqueCategories: ', uniqueCategories); const { data: categoriesData, error: categoriesError } = await supabase .from('categories') .insert(uniqueCategories); console.log({ categoriesData }); console.log({ categoriesError }); if (!categoriesData || categoriesError) { return { success: false, ...genericError({ message: 'Error importing categories', path: 'Csv import resolver: try' }), }; } // create category_items - 补全逻辑 // 建立分类名称到ID的映射,提升查找效率 const categoryNameToId = new Map(categoriesData.map(cat => [cat.name, cat.id])); // 按分类名称分组插入后的条目 const itemsByCategory: Record<string, {id: number}[]> = {}; data.forEach((rawItem, index) => { const categoryName = rawItem.category_name; const item = bulkInsertData[index]; if (!itemsByCategory[categoryName]) { itemsByCategory[categoryName] = []; } itemsByCategory[categoryName].push(item); }); // 生成符合要求的关联数组 const newCategoryItems = Object.entries(itemsByCategory).flatMap(([categoryName, items]) => { const categoryId = categoryNameToId.get(categoryName); if (!categoryId) return []; // 处理分类未找到的异常情况 return items.map((item, posIndex) => ({ category_id: categoryId, item_id: item.id, position: posIndex + 1 // position从1开始自增 })); }); // 批量插入关联表 const { data: categoryItemsData, error: categoryItemsError } = await supabase .from('category_items') .insert(newCategoryItems); if (!categoryItemsData || categoryItemsError) { return { success: false, ...genericError({ message: 'Error importing category items', path: 'Csv import resolver: try' }), }; } } return { success: true, errors: null, }; } catch (err) { console.log({ err }); return { success: false, ...genericError({ message: 'Error importing items', path: 'Csv import resolver: catch' }), }; } }; export default csvImport;
关键逻辑说明
- 分类映射表:用
Map存储分类名称与ID的对应关系,避免多次遍历数组查找,提升性能。 - 按分类分组:结合原始数据的分类名称,将插入后的条目按分类归类,保证同一分类下的条目顺序与原始CSV一致。
- 生成关联条目:对每个分类下的条目,按顺序分配从1开始的
position值,最后合并成符合要求的关联数组。 - 异常处理:补充了分类未找到的容错逻辑,以及关联表插入的错误处理,保证流程的健壮性。
内容的提问来源于stack exchange,提问作者J. Jackson
相关产品推荐
相关产品推荐

