gpt4 book ai didi

javascript - 如何有效地比较具有不同键但可能匹配值的2个对象?

转载 作者:搜寻专家 更新时间:2023-10-31 23:57:32 25 4
gpt4 key购买 nike

我有2个对象,一个来自SQL数据库,另一个来自JSON REST API。在使用来自api的新数据更新数据库中的行之前,我不仅要检查ID是否已在数据库中出现(这意味着要进行更新而不是插入操作),还要检查属性的大部分。原因是,当它确实在数据库端更新时,会添加一个附加的“lastUpdate”日期时间以供以后在PowerBI中进行处理,如果我仅检查ID,则每次从API中输入条目时都会触发“lastUpdate”即使它的属性没有实际更新,也已经存在于数据库中。两侧的单个对象(它们以阵列形式出现)如下:

案例和注释:

重要:本部分是根据Nina Scholz要求的(现在)接受的解决方案添加的。阅读时请记住这一点。

  • 如果路径在API端不是完全可遍历的(即其父级为null),则应返回Null。这样的一个示例是数据库的侧面callerLocationID的路径在API上为callerLocation.id,但是,如果未设置callerLocation,则父callerLocation已经是null,因此使得id无法访问
  • 如果路径在两侧都是完全可遍历的,则需要比较这些值。
  • 如果无法在API端遍历路径,则应为null。例如,然后我可以将callerLocationID: nullcallerLocation.id进行比较,因为后者是null,并且nullnull
  • 相同
    遍历所有路径并比较所有值后,我需要知道“是的,它们都是相同的”( true)还是“否,它们是不相同的”( false)。如果不需要知道它们是否不相同,则将整个对象发送给更新。
  • 如果其中任何一个是null,则数据库一侧的路径基本上是固定的,因为这是因为允许在数据库中使用
  • DB端所有以ID结尾的属性(incidentID除外)均引用API中的单个嵌套id值。例如callerID引用caller.idcallerBranchID引用callerBranch.idoperatorID引用operator.id
  • 某些异常(exception)是:
  • impact引用impact.name
  • urgency引用urgency.name
  • priority引用priority.name
  • duration引用duration.name
  • escalationOperator引用escalationOperator.id
  • 来自API的所有optionalField东西都可以忽略


  • // Database Object
    {
    incidentID: '0dc1a10f-2899-485a-b814-f72f29c9a15a',
    status: 'secondLine',
    briefDescription: 'Support niet bereikbaar',
    callDate: '2018-04-10T19:01:00.000Z',
    lastUpdate: '2018-04-18T14:02:17.000Z',
    number: 'M1804 021',
    request: '10-04-2018 21:02 Middelkoop, Paul: \nIk kan de servicedesk niet bereiken, telkens in gesprek',
    callerID: '4e723042-0037-4e05-a362-e65c620ba734',
    callerBranchID: 'f66e7804-b57a-4418-a991-997e574ead29',
    callerLocationID: null,
    externalNumber: null,
    categoryID: 'cafb0af8-e43a-4391-ac9e-a0345abbcc4f',
    subcategoryID: 'f56099a9-7c60-45e3-94b4-6555a79d4bd7',
    callTypeID: '04b678a6-791e-4662-9bc8-97573555f15e',
    entryTypeID: 'a9c486fd-a93e-565e-bfeb-17619fafe1a8',
    branchID: null,
    locationID: null,
    impact: null,
    urgency: null,
    priority: null,
    duration: null,
    operatorID: 'a17aba85-13a7-4ac6-8c57-693a512b633e',
    operatorGroupID: 'a17aba85-13a7-4ac6-8c57-693a512b633e',
    supplierID: null,
    targetDate: '2019-04-10T15:30:00.000Z',
    onHold: false,
    onHoldDate: null,
    onHoldDuration: 0,
    feedbackMessage: null,
    feedbackRating: null,
    processingStatus: 'Afgemeld',
    completed: true,
    completedDate: '2018-04-10T19:09:00.000Z',
    closed: true,
    closedDate: null,
    closureCode: null,
    creatorID: '226082ea-8d74-4dee-ae1e-74c33c883792',
    creationDate: '2018-04-10T19:02:34.000Z',
    timeSpent: 0,
    timeSpentFirstLine: 0,
    timeSpentSecondLineAndPartials: 0,
    costs: 0,
    escalationStatus: null,
    escalationReason: null,
    escalationOperator: null,
    modifier: '226082ea-8d74-4dee-ae1e-74c33c883792',
    modificationDate: '2018-04-10T19:12:08.000Z',
    expectedTimeSpent: 0,
    majorCall: false,
    majorCallID: null,
    publishToSSD: false,
    monitored: false,
    archivingReason: null
    }



    // API Object
    {
    id: '0dc1a10f-2899-485a-b814-f72f29c9a15a',
    status: 'secondLine',
    number: 'M1804 021',
    request: '10-04-2018 21:02 Middelkoop, Paul: \nIk kan de servicedesk niet bereiken, telkens in gesprek',
    requests: '/tas/api/incidents/id/0dc1a10f-2899-485a-b814-f72f29c9a15a/requests',
    action: '/tas/api/incidents/id/0dc1a10f-2899-485a-b814-f72f29c9a15a/actions',
    attachments: '/tas/api/incidents/id/0dc1a10f-2899-485a-b814-f72f29c9a15a/attachments',
    caller: {
    id: '4e723042-0037-4e05-a362-e65c620ba734',
    dynamicName: 'Mafficioli del Castelletto, Richard',
    branch: {
    id: 'f66e7804-b57a-4418-a991-997e574ead29',
    name: 'Ask Roger! Delft',
    clientReferenceNumber: '',
    timeZone: 'Europe/Amsterdam',
    extraA: null,
    extraB: null
    }
    },
    callerBranch: {
    id: 'f66e7804-b57a-4418-a991-997e574ead29',
    name: 'Ask Roger! Delft',
    clientReferenceNumber: '',
    timeZone: 'Europe/Amsterdam',
    extraA: null,
    extraB: null
    },
    callerLocation: null,
    branchExtraFieldA: null,
    branchExtraFieldB: null,
    briefDescription: 'Support niet bereikbaar',
    externalNumber: '',
    category: {
    id: 'cafb0af8-e43a-4391-ac9e-a0345abbcc4f',
    name: 'Communicatie'
    },
    subcategory: {
    id: 'f56099a9-7c60-45e3-94b4-6555a79d4bd7',
    name: 'Vaste telefonie'
    },
    callType: {
    id: '04b678a6-791e-4662-9bc8-97573555f15e',
    name: 'Klacht'
    },
    entryType: {
    id: 'a9c486fd-a93e-565e-bfeb-17619fafe1a8',
    name: 'Mondeling'
    },
    object: null,
    branch: null,
    location: null,
    impact: null,
    urgency: null,
    priority: null,
    duration: null,
    targetDate: '2019-04-10T15:30:00.000+0000',
    onHold: false,
    onHoldDate: null,
    onHoldDuration: 0,
    feedbackMessage: null,
    feedbackRating: null,
    operator: {
    id: 'a17aba85-13a7-4ac6-8c57-693a512b633e',
    status: 'operatorGroup',
    name: 'Systeembeheer'
    },
    operatorGroup: {
    id: 'a17aba85-13a7-4ac6-8c57-693a512b633e',
    name: 'Systeembeheer'
    },
    supplier: null,
    processingStatus: {
    id: '70b2967d-e248-4ff9-a632-ec044410d5a6',
    name: 'Afgemeld'
    },
    completed: true,
    completedDate: '2018-04-10T19:09:00.000+0000',
    closed: true,
    closedDate: '2018-04-10T19:12:00.000+0000',
    closureCode: null,
    timeSpent: 0,
    timeSpentFirstLine: 0,
    timeSpentSecondLineAndPartials: 0,
    costs: 0,
    escalationStatus: null,
    escalationReason: null,
    escalationOperator: null,
    callDate: '2018-04-10T19:01:00.000+0000',
    creator: {
    id: '226082ea-8d74-4dee-ae1e-74c33c883792',
    name: 'Middelkoop, Paul'
    },
    creationDate: '2018-04-10T19:02:34.000+0000',
    modifier: {
    id: '226082ea-8d74-4dee-ae1e-74c33c883792',
    name: 'Middelkoop, Paul'
    },
    modificationDate: '2018-04-10T19:12:08.000+0000',
    majorCall: false,
    majorCallObject: null,
    publishToSsd: false,
    monitored: false,
    expectedTimeSpent: 0,
    archivingReason: null,
    optionalFields1: {
    boolean1: false,
    boolean2: false,
    boolean3: false,
    boolean4: false,
    boolean5: false,
    number1: 0,
    number2: 0,
    number3: 0,
    number4: 0,
    number5: 0,
    date1: null,
    date2: null,
    date3: null,
    date4: null,
    date5: null,
    text1: '',
    text2: '',
    text3: '',
    text4: '',
    text5: '',
    memo1: null,
    memo2: null,
    memo3: null,
    memo4: null,
    memo5: null,
    searchlist1: null,
    searchlist2: null,
    searchlist3: null,
    searchlist4: null,
    searchlist5: null
    },
    optionalFields2: {
    boolean1: false,
    boolean2: false,
    boolean3: false,
    boolean4: false,
    boolean5: false,
    number1: 0,
    number2: 0,
    number3: 0,
    number4: 0,
    number5: 0,
    date1: null,
    date2: null,
    date3: null,
    date4: null,
    date5: null,
    text1: '',
    text2: '',
    text3: '',
    text4: '',
    text5: '',
    memo1: null,
    memo2: null,
    memo3: null,
    memo4: null,
    memo5: null,
    searchlist1: null,
    searchlist2: null,
    searchlist3: null,
    searchlist4: null,
    searchlist5: null
    }
    }

    到目前为止我已经做了什么
  • 遍历API对象的数组,并使用Fuse.JS(对于完美匹配,将阈值设置为0,对于每个单个对象,检查ID是否为数据库对象的数组)
  • 使用1的结果与UnderscoreJS的.first,.keys和.pick方法的组合来确定当前迭代中2个对象中哪些键相同,目的是快速检查那些

  •     // tdIncidents is the array of objects from the API
    // dbIncidents is the array of objects from the database
    // tdinci is my iterator, consider it the "i" in the for loop
    // at this point it has already been confirmed that both dbIncidents and tdIncidents have at least 1 entry thus using [0] won't give any problems
    const db = _.first(fuse.search(tdIncidents[tdinci].id)),
    td = tdIncidents[tdinci],
    dbKeys = _.keys(dbIncidents[0]),
    tdKeys = _.keys(tdIncidents[0]),
    identicalKeysTd = _.pick(td, (value, key) => dbKeys.includes(key)),
    identicalKeysDb = _.pick(db, (value, key) => tdKeys.includes(key));

    sameKeysTd将导致:

    { status: 'secondLine',
    number: 'M1804 021',
    request: '10-04-2018 21:02 Middelkoop, Paul: \nIk kan de servicedesk niet bereiken, telkens in gesprek',
    briefDescription: 'Support niet bereikbaar',
    externalNumber: '',
    impact: null,
    urgency: null,
    priority: null,
    duration: null,
    targetDate: '2019-04-10T15:30:00.000+0000',
    onHold: false,
    onHoldDate: null,
    onHoldDuration: 0,
    feedbackMessage: null,
    feedbackRating: null,
    processingStatus: { id: '70b2967d-e248-4ff9-a632-ec044410d5a6', name: 'Afgemeld' },
    completed: true,
    completedDate: '2018-04-10T19:09:00.000+0000',
    closed: true,
    closedDate: '2018-04-10T19:12:00.000+0000',
    closureCode: null,
    timeSpent: 0,
    timeSpentFirstLine: 0,
    timeSpentSecondLineAndPartials: 0,
    costs: 0,
    escalationStatus: null,
    escalationReason: null,
    escalationOperator: null,
    callDate: '2018-04-10T19:01:00.000+0000',
    creationDate: '2018-04-10T19:02:34.000+0000',
    modifier:
    { id: '226082ea-8d74-4dee-ae1e-74c33c883792',
    name: 'Middelkoop, Paul' },
    modificationDate: '2018-04-10T19:12:08.000+0000',
    majorCall: false,
    monitored: false,
    expectedTimeSpent: 0,
    archivingReason: null }

    sameKeysDb将导致:

    { status: 'secondLine',
    briefDescription: 'Support niet bereikbaar',
    callDate: '2018-04-10T19:01:00.000Z',
    number: 'M1804 021',
    request: '10-04-2018 21:02 Middelkoop, Paul: \nIk kan de servicedesk niet bereiken, telkens in gesprek',
    externalNumber: null,
    impact: null,
    urgency: null,
    priority: null,
    duration: null,
    targetDate: '2019-04-10T15:30:00.000Z',
    onHold: false,
    onHoldDate: null,
    onHoldDuration: 0,
    feedbackMessage: null,
    feedbackRating: null,
    processingStatus: 'Afgemeld',
    completed: true,
    completedDate: '2018-04-10T19:09:00.000Z',
    closed: true,
    closedDate: null,
    closureCode: null,
    creationDate: '2018-04-10T19:02:34.000Z',
    timeSpent: 0,
    timeSpentFirstLine: 0,
    timeSpentSecondLineAndPartials: 0,
    costs: 0,
    escalationStatus: null,
    escalationReason: null,
    escalationOperator: null,
    modifier: '226082ea-8d74-4dee-ae1e-74c33c883792',
    modificationDate: '2018-04-10T19:12:08.000Z',
    expectedTimeSpent: 0,
    majorCall: false,
    monitored: false,
    archivingReason: null }
  • 此时,我认为我可以使用UnderscoreJS的identicalKeys(.isEqual)检查这两个_.isEqual(identicalKeysDb, identicalKeysTd)对象的相等性,但无济于事。除了我直接在数据库中存储一些键而没有附加“ID”(可以在数据库端固定)这一事实之外,更紧迫的问题是数据库将为诸如null之类的值提供externalNumber,但API会给出''

  • 在最近的一次尝试中,我尝试了ES6中的许多其他功能,包括普通JS和UnderscoreJS(太多的提及和代码已被删除,并且在我的“撤消”链上不再可用),但是我根本找不到任何有效的方法我真的不想硬编码一个巨大的 if ()来检查每个属性是否与对应属性相对应。我不介意需要一些节点程序包来简化此比较,因此,如果绝对是解决方案,请也共享它。

    那些实际更改的对象我推送到一个名为 existingIncidents的数组,该数组随后与任何新事件一起返回。发生这种情况如下:

    async filterIncidents() {
    const dbIncidents = await this.getDbIncidents(this.lastFetchTimestamp),
    fuseOpts = {
    'shouldSort': true,
    'findAllMatches': true,
    'threshold': 0,
    'location': 0,
    'distance': 100,
    'maxPatternLength': 36,
    'minMatchCharLength': 36,
    'keys': ['incidentID']
    },
    fuse = new Fuse(dbIncidents, fuseOpts),
    tdIncidents = await this.getTdIncidents(this.lastFetchTimestamp);

    const existIncidents = [],
    newIncidents = [];

    if (!dbIncidents.length) {
    for (const tdinci in tdIncidents) {
    newIncidents.push(tdIncidents[tdinci]);
    }
    } else {
    for (const tdinci in tdIncidents) {
    if (fuse.search(tdIncidents[tdinci].id).length) {
    // The value checking magic I need has to happen here. Some pseudo code:
    // if (values are different) {
    existIncidents.push(tdIncidents[tdinci]);
    // } else {
    // do nothing
    // }
    } else {
    newIncidents.push(tdIncidents[tdinci]);
    }
    }
    }

    return {
    'new': newIncidents,
    'existing': existIncidents
    };
    }

    编辑:在底部添加了整个功能

    最终编辑:我在这里将Nkit Schulz的runkit链接转储到最终解决方案的实现,因为我不得不将其调整到我的确切用例,并且共享很重要,也许将来会帮助其他人。
    固定链接: https://runkit.com/favna/so-compare-objects

    最佳答案

    这是一种通过将数组用于不同样式的对象以及指向每个对象的属性的相对路径的方法。

    关键功能是单个函数getValue,它接受一个对象和一个通向所需属性的关键数组,并返回找到的值或该链的最后找到的值。

    另一个函数迭代给定的关系对象,并(实际上)显示两个值,以进行补偿和稍后的操作,例如更新或其他需要的操作。

    function getValue(object, keys) {
    return keys.reduce((o, k) => o && typeof o === 'object' ? o[k] : o, object);
    }

    function compaire(objects, relations) {
    relations.forEach(relation => {
    var values = relation.map((keys, i) => getValue(objects[i], keys));
    console.log(...values);
    });
    }

    var objectA = { foo: { bar: 42 }, a: { b: { c: 'baz' } }, callerLocation: null },
    objectB = { fooBar: 42, nested: { abc: 'bau' }, callerLocationID: null },
    objects = [objectA, objectB],
    relations = [
    [['foo', 'bar'], ['fooBar']],
    [['a', 'b', 'c'], ['nested', 'abc']],
    [['callerLocation', 'id'], ['callerLocationID']],
    [['x', 'u'], ['x', 'y']]
    ];

    compaire(objects, relations);

    关于javascript - 如何有效地比较具有不同键但可能匹配值的2个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49901436/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com