【问题标题】:Typescript - Processing Large JSON file with filters and sortTypescript - 使用过滤器和排序处理大型 JSON 文件
【发布时间】:2021-11-05 16:02:52
【问题描述】:

我有以下 json 架构要使用 Typescript 处理(具有 100 MB 条目的文件)。

[
   {
      "firstName":"Emma",
      "lastName":"Sall",
      "country":"US",
      "email":"test@hotmail.com",
      "dob":"1944-05-05T13:14:32.526Z",
      "mfa":"SMS",
      "amt":962169704,
      "createdDate":"2020-08-15T20:07:24.157Z",
      "referredBy":null
   },
   {
      "firstName":"Darren",
      "lastName":"test",
      "country":"ES",
      "email":"test334@yahoo.com",
      "dob":"1944-02-11T19:44:58.715Z",
      "mfa":"SMS",
      "amt":239723064,
      "createdDate":"2020-07-12T12:39:47.553Z",
      "referredBy":null
   },
...
   ...
      ...
]

在这两行对数组进行排序时出现此错误(下面的完整代码):

a[accountSearchCriteria.sortField] <
b[accountSearchCriteria.sortField]

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Account'. No index signature with a parameter of type 'string' was found on type 'Account'.

我正在使用以下代码来处理文件main.ts

import fs from 'fs';
const accountSearchCriteria: AccountSearchCriteria = {
                country: 'CA',
                mfa: 'SMS',
                name: 'TEST',
                sortField: 'amt'
            };
const jsonPath = './test/src.json';
        const rawAccounts = fs.readFileSync(jsonPath, 'utf-8');
        let accounts: Account[] = JSON.parse(rawAccounts);
        if (accountSearchCriteria) {
            if (accountSearchCriteria.name) {
                accounts = accounts.filter(
                    account =>
                        account.firstName.toLowerCase() ===
                            accountSearchCriteria.name.toLowerCase() ||
                        account.lastName.toLowerCase() ===
                            accountSearchCriteria.name.toLowerCase()
                );
            }
            if (accountSearchCriteria.country) {
                accounts = accounts.filter(
                    account =>
                        account.country.toLowerCase() ===
                        accountSearchCriteria.country.toLowerCase()
                );
            }
            if (accountSearchCriteria.mfa) {
                accounts = accounts.filter(
                    account => account.mfa === accountSearchCriteria.mfa
                );
            }
            if (accountSearchCriteria.sortField) {
                 accounts.sort((a, b) =>
                     a[accountSearchCriteria.sortField] <
                     b[accountSearchCriteria.sortField]
                         ? -1
                         : 1
                 );
            }
            return accounts;
        }
        return accounts;

接口定义如下account.ts:

export interface Account {
    firstName: string;
    lastName: string;
    country: string;
    email: string;
    dob: string;
    mfa?: MFA;
    amt: number;
    createdDate: string;
    referredBy?: string;
}
export enum MFA {
    SMS = 'SMS',
    TOTP = 'TOTP'
}

export interface AccountSearchCriteria {
    country?: string;
    mfa?: string;
    name?: string;
    sortField?: string;
}

此外,代码需要很长时间来处理我想要读取的文件,它是 100 MB,我针对一个小文件对其进行了测试,它运行良好。有没有更快的方法来改进代码并提高效率?

【问题讨论】:

  • sortField 的类型是 string | undefined,但在您进行 a[...] &lt; b[...] 比较时缩小到仅 string。 TS 抱怨的原因是 a 不是一个可以将任意字符串作为键的对象。不允许使用a[arbitraryString]。为了使它起作用,您有 3 个选项。 1) 使用index signature 使a 通常可索引 2) 使用the Record type 使a 通常可索引
  • 3) 将sortField 的类型更改为keyof Account 或以其他方式确保sortField 仅作为Account 接口的有效键输入。这可能是你最好的选择,因为在你的Account 接口中允许任意字符串并不是最好的主意(即使它在技术上可能有效)
  • @nullromo 非常感谢 cmets,你能给我一个选项号的例子吗? 3个好吗?
  • 是的,我会尽快发布答案。
  • @nullromo 非常感谢 .. 另外,不确定是否有办法改进它以读取更大的文件 .. 因为处理它们需要很长时间

标签: javascript node.js json typescript


【解决方案1】:

这是一个稍微简化的 cmets 示例

export interface Account {
    firstName: string;
    lastName: string;
    country: string;
    email: string;
    dob: string;
    mfa?: MFA;
    amt: number;
    createdDate: string;
    referredBy?: string;
}
export enum MFA {
    SMS = 'SMS',
    TOTP = 'TOTP'
}

export interface AccountSearchCriteria {
    country?: string;
    mfa?: string;
    name?: string;
    sortField?: keyof Account; // here I made sortField into a key of Account
}

const accountSearchCriteria: AccountSearchCriteria = {
  sortField: 'amt'
};

const doThing = (accounts: Account[]) => {
  // make sure the sortField is defined
  if(!accountSearchCriteria.sortField) {
    return;
  }
  const sortField = accountSearchCriteria.sortField; // sortField has type keyof Account
  accounts.sort((a, b) => {
    const aField = a[sortField]; // here you can access the field no problem
    // The type of aField is string | number | undefined because those are all the possible values for an attribute of an Account.
    return a[sortField] < b[sortField] ? -1 : 1 // here you have an issue because at least one of the attributes in the Account interface is possibly undefined.
    // so you need to determine how exactly you want to handle this
  });
  return accounts;
}

这是TS playground上的代码链接

您可以使用它来将鼠标悬停在内容上并清楚地查看类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    • 2016-11-03
    • 2011-05-02
    • 2017-03-04
    相关资源
    最近更新 更多