如何用Normalizr转换JSON数组,实现双ID快速查询费用
如何构建支持双维度查询的旅行费用数据结构
我有一组旅行费用的JSON数组,想要转换成既能快速通过travelExpenseId查询单条费用,又能通过tripId批量查询对应行程下所有费用的结构。目前我用Normalizr的Schema只实现了按travelExpenseId索引的功能,希望能新增expensesByTripId实体来实现按行程ID查询的需求。
原始费用数据
[ { "travelExpenseId":11, "tripId":2, "paymentPurpose":"some payment purpose 2", "receiptNumber":"EF12312_2", "receiptDate":"2018-09-30T00:00:00", "receiptPrice":107000.0, "receiptCurrency":"руб." }, { "travelExpenseId":10, "tripId":2, "paymentPurpose":"some payment purpose 1", "receiptNumber":"EF12312_1", "receiptDate":"2018-09-30T00:00:00", "receiptPrice":107000.0, "receiptCurrency":"руб." } ]
当前使用的Normalizr Schema
export const expenseSchema = new schema.Entity('expenses', {}, { idAttribute: 'travelExpenseId' }); export const expensesListSchema = [expenseSchema];
当前转换结果
data: { entities: { expenses: { '10': { travelExpenseId: 10, tripId: 2, paymentPurpose: 'some payment purpose 1', receiptNumber: 'EF12312_1', receiptDate: '2018-09-30T00:00:00', receiptPrice: 107000, receiptCurrency: 'руб.' }, '11': { travelExpenseId: 11, tripId: 2, paymentPurpose: 'some payment purpose 2', receiptNumber: 'EF12312_2', receiptDate: '2018-09-30T00:00:00', receiptPrice: 107000, receiptCurrency: 'руб.' } } }, result: [ 11, 10 ] }
期望的转换结果
data: { entities: { expensesByTripId: { '2': [10, 11], }, expenses: { '10': { travelExpenseId: 10, tripId: 2, paymentPurpose: 'some payment purpose 1', receiptNumber: 'EF12312_1', receiptDate: '2018-09-30T00:00:00', receiptPrice: 107000, receiptCurrency: 'руб.' }, '11': { travelExpenseId: 11, tripId: 2, paymentPurpose: 'some payment purpose 2', receiptNumber: 'EF12312_2', receiptDate: '2018-09-30T00:00:00', receiptPrice: 107000, receiptCurrency: 'руб.' } } }, result: [ 11, 10 ] }
解决方案
下面提供两种可行的方案,一种基于你正在使用的Normalizr扩展,另一种是手动转换的轻量方案:
方案一:扩展Normalizr实现双维度索引
Normalizr本身没有直接支持多维度分组的API,但我们可以通过两种方式补充这个功能:
方式1:normalize后手动构建分组
这是最直观的方式,先完成原有Normalizr的转换,再遍历结果生成expensesByTripId:
import { normalize } from 'normalizr'; // 你的原有Schema export const expenseSchema = new schema.Entity('expenses', {}, { idAttribute: 'travelExpenseId' }); export const expensesListSchema = [expenseSchema]; // 原始费用数据 const rawExpenses = [/* 你的原始JSON数组 */]; // 执行原有normalize流程 const normalizedData = normalize(rawExpenses, expensesListSchema); // 构建tripId到expenseId的映射 const expensesByTripId = {}; Object.values(normalizedData.entities.expenses).forEach(expense => { const tripIdStr = expense.tripId.toString(); if (!expensesByTripId[tripIdStr]) { expensesByTripId[tripIdStr] = []; } expensesByTripId[tripIdStr].push(expense.travelExpenseId); }); // 将映射合并到entities中 normalizedData.entities.expensesByTripId = expensesByTripId; // 现在normalizedData就是你想要的结构
方式2:利用processStrategy在转换时同步构建分组
如果你想在Normalizr处理实体的过程中就完成分组,可以使用processStrategy钩子,不过需要注意维护一个临时的映射对象:
import { schema, normalize } from 'normalizr'; // 临时存储tripId到expenseId的映射 const tripExpenseMap = {}; const expenseSchema = new schema.Entity('expenses', {}, { idAttribute: 'travelExpenseId', // 处理每个expense时同步更新映射 processStrategy: (expense) => { const tripIdStr = expense.tripId.toString(); if (!tripExpenseMap[tripIdStr]) { tripExpenseMap[tripIdStr] = []; } tripExpenseMap[tripIdStr].push(expense.travelExpenseId); return expense; } }); const expensesListSchema = [expenseSchema]; const rawExpenses = [/* 你的原始JSON数组 */]; const normalizedData = normalize(rawExpenses, expensesListSchema); // 将映射添加到entities normalizedData.entities.expensesByTripId = tripExpenseMap;
方案二:手动转换数据(不依赖Normalizr)
如果你的场景不需要Normalizr的其他复杂功能,手动转换会更轻量、灵活:
const rawExpenses = [/* 你的原始JSON数组 */]; const transformedData = { entities: { expenses: {}, expensesByTripId: {} }, result: [] }; rawExpenses.forEach(expense => { // 按travelExpenseId存储单条费用 transformedData.entities.expenses[expense.travelExpenseId] = expense; // 按tripId分组存储expenseId const tripIdStr = expense.tripId.toString(); if (!transformedData.entities.expensesByTripId[tripIdStr]) { transformedData.entities.expensesByTripId[tripIdStr] = []; } transformedData.entities.expensesByTripId[tripIdStr].push(expense.travelExpenseId); // 保留原始数据的顺序 transformedData.result.push(expense.travelExpenseId); }); // transformedData就是你期望的最终结构
内容的提问来源于stack exchange,提问作者AuthorProxy
相关产品推荐
相关产品推荐

