如何根据字段OrderNo和Location合并两个对象数组?

时间:2019-04-15 18:38:49

标签: javascript reactjs

我有两个API响应

第一个API响应(ProjectAPI.post('/ ALLAPI / API1',null,null,requestBody的响应))-参见问题的后面部分

[
 {
"Location": "Boston",
"OrderNo": "406643",
"Qty": "46.1650",
"OrderDate": null,
"Status": null
}

]

第二个API响应(ProjectAPI.post('/ ALLAPI / API2',null,null,requestBody的响应))-参见问题的后面部分

[
 {
"Location": "Boston",
"OrderNo": "406643",
"Qty": "22.27",
"OrderDate": "28/11/0018",
"Status": null
},
{
"Location": "Boston",
"OrderNo": "526209",
"Qty": "21.94",
"OrderDate": "01/03/0019",
"Status": null
 },
 {
"Location": "Boston",
"OrderNo": "526209",
"Qty": "65.36",
"OrderDate": "01/03/0019",
"Status": null
 }
]

现在两个API都有一个“数量”字段,我必须在需要同时包含两个数量的地方创建一个新变量。如果对于特定的OrderNo和Location组合,说Qty1-存在第一个API响应字段Qty但不存在第二个API Qty字段,那么我们应该将Qty2插入为0,同样如果Qty2-存在第二个APIs响应字段Qty但第一个API数量字段不存在,那么我们应该将数量1插入0。

我们还要考虑两个API中的任何一个都可以完全返回空白数组

请注意,比较参数为OrderNo和Location。

我想基本上合并两个API响应并创建一个CombinedResponse

我的组合响应必须在对象数组中包含三个对象

[
 {
"Location": "Boston",
"OrderNo": "406643",
"Qty1": "46.1650",
"Qty2": "22.27",
"OrderDate": "28/11/0018",
"Status": null
 },
 {
"Location": "Boston",
"OrderNo": "526209",
"Qty1": "0",
"Qty2": "21.94",
"OrderDate": "01/03/0019",
"Status": null
  },
  {
"Location": "Boston",
"OrderNo": "526209",
"Qty1": "0",
"Qty2": "65.36",
"OrderDate": "01/03/0019",
"Status": null
 }
]

我已经使用Lodash了,但是得到了一些异常结果

我的代码

 ProjectAPI.post('/ALLAPI/API1', null, null, requestBody)
    .then((response) => {//1st API response (as mentioned above)
      const combinedResponse = [];
      for (let i = 0; i < response.length; i = i + 1) {
        const obj = response[i];
        obj.Qty1 = response[i].Qty;
        obj.Qty2 = 0;
        combinedResponse.push(obj);
      }
      ProjectAPI.post('/ALLAPI/API2', null, null, requestBody)
        .then((innerResponse) => {//2nd API response (as mentioned above)
          for (let i = 0; i < innerResponse.length; i = i + 1) {
            const outerIndex = _.findIndex(combinedResponse, (o) => { return o.Location === innerResponse[i].Location && o.OrderNo === innerResponse[i].OrderNo; });
            let obj = {};
            if(outerIndex === -1) {
              obj = innerResponse[i];
              obj.Qty1 = 0;
              obj.Qty2 = innerResponse[i].Qty;
              combinedResponse.push(obj);
            } else {
              combinedResponse[outerIndex].Qty2 = innerResponse[i].Qty;
            }
          }
          this.setState({ combinedResponse: combinedResponse });
        }).catch((err) => {
          console.log('There was an error with ', err);
        });
    }).catch((err) => {
      console.log('There was an error with ', err);
    });

我的代码没有显示最后一个/第三个对象(仅获取第一个两个对象)

[
 {
"Location": "Boston",
"OrderNo": "406643",
"Qty1": "46.1650",
"Qty2": "22.27",
"OrderDate": "28/11/0018",
"Status": null
 },
 {
"Location": "Boston",
"OrderNo": "526209",
"Qty1": "0",
"Qty2": "21.94",
"OrderDate": "01/03/0019",
"Status": null
  }
]

如果有人可以纠正我的代码以使我得到正确的CombinedResponse,这将非常有帮助。我对Lodash / JQuery解决方案不感兴趣。我想要一个普通香草JS解决方案。请提供通用解决方案。有人可以在这方面帮助我。在我的代码中,最后一个对象未​​显示在对象的最终数组中。我的方法也很复杂。如果有人可以提供更简单的响应以及小提琴/ JSFiddle,那么这对我会有很大帮助。

如果有人回答我的查询,请忽略API调用,只需使用两个API响应即可。

在Plain ES5或ES6中需要一个解决方案,而在JQuery / Underscore / Lodash中则不需要。

4 个答案:

答案 0 :(得分:0)

当JS本机函数简洁时,我不希望使用诸如lodash之类的依赖项。

1)我建议在将map字段重命名为Qty时,使用Qty1 (mdn)从您的第一个响应中初始化您的组合响应。

2)然后使用forEach (mdn)

遍历第二个响应

3)使用find (mdn)从您的第一个响应中找到相应的顺序。

4)如果您在响应1中找到了相应的订单,请更新其Qty2字段。否则,请在您的combinedResponses中插入新订单。

let response1 = [
  {
    "Location": "Boston",
    "OrderNo": "406643",
    "Qty": "46.1650",
    "OrderDate": null,
    "Status": null
  }
];

let response2 = [
  {
    "Location": "Boston",
    "OrderNo": "406643",
    "Qty": "22.27",
    "OrderDate": "28/11/0018",
    "Status": null
  },
  {
    "Location": "Boston",
    "OrderNo": "526209",
    "Qty": "21.94",
    "OrderDate": "01/03/0019",
    "Status": null
  },
  {
    "Location": "Boston",
    "OrderNo": "526209",
    "Qty": "65.36",
    "OrderDate": "01/03/0019",
    "Status": null
  }
];

let combinedResponses = response1.map(({Location, OrderNo, Qty, OrderDate, Status}) =>
    ({Location, OrderNo, Qty1: Qty, Qty2: 0, OrderDate, Status,}));

response2.forEach(({Location, OrderNo, Qty, OrderDate, Status}) => {
  let find = combinedResponses.find(({Location: locationC, OrderNo: orderNoC})=> locationC === Location && orderNoC === OrderNo);
  if (find)
    find.Qty2 = Qty;
  else
    combinedResponses.push({Location, OrderNo, Qty1: 0, Qty2: Qty, OrderDate, Status,});
});

console.log(combinedResponses);

PS,同样值得一提的是,您应该研究展平承诺/然后嵌套以使其更具可读性。

答案 1 :(得分:0)

鉴于orderNo唯一地标识一个实体,该实体将是一种简单,通用且易于理解的解决方案:

let array1 = [{
  "Location": "Boston",
  "OrderNo": "406643",
  "Qty": "46.1650",
  "OrderDate": null,
  "Status": null
}]

let array2 = [{
    "Location": "Boston",
    "OrderNo": "406643",
    "Qty": "22.27",
    "OrderDate": "28/11/0018",
    "Status": null
  },
  {
    "Location": "Boston",
    "OrderNo": "526209",
    "Qty": "21.94",
    "OrderDate": "01/03/0019",
    "Status": null
  },
  {
    "Location": "Boston",
    "OrderNo": "526209",
    "Qty": "65.36",
    "OrderDate": "01/03/0019",
    "Status": null
  }
]
let mergedArray = [];
let orderNumbers = array2.map(x => x.OrderNo);
array1.forEach((order, i) => {
  let mergedOrder = {
    "Location": order.Location,
    "OrderNo": order.OrderNo,
    "Qty1": order.Qty,
    "OrderDate": order.OrderDate,
    "Status": order.Status
  }
  let index = orderNumbers.indexOf(order.OrderNo);
  if (index <= 0) {
    mergedOrder.Qty2 = array2[index].Qty;
    //remove used element
    array2.splice(index, 1);
    orderNumbers.splice(index, 1);
  } else {
    mergedOrder.Qty2 = "0";
  }
  mergedArray.push(mergedOrder);
})
//insert the remaining elements with 0 as qty1
array2.forEach(order => {
  let mergedOrder = {
    "Location": order.Location,
    "OrderNo": order.OrderNo,
    "Qty2": order.Qty,
    "OrderDate": order.OrderDate,
    "Status": order.Status
  }
  mergedOrder.Qty1 = "0";
  mergedArray.push(mergedOrder);

});

console.log(mergedArray);

其中array1array2是您的2条回复。

还请注意,例如,使用indexOf代替find有利于浏览器兼容性(尤其是IE)。

编辑:添加了jsfiddle。请原谅我不要在任何地方都使用camelCase,但希望您能理解。

答案 2 :(得分:0)

问题是您的两个匹配mongoclientoptions vs mongoclientsettingsLocation的项目都在同一个orderNo数组中,因此当您遍历该数组并找到带有{{ 1}}和innerResponse,分别设置Location: 'Boston'orderNo: 526209,然后再次循环时,找到匹配的元素,并在obj.Qty = 0块中用{匹配obj.Qty2 = innerResponse[i].Qty;中的值,因此您要么需要设置else

解决方案是,如果没有匹配的Qty2而不是设置objQt1 = innerResponse[i].Qty,而如果没有匹配的obj.Qty1 = 0;则设置obj.Qty2 = innerResponse[i].Qty;然后打开在下一个循环中,它将添加一个obj,您将获得两个值。

更好的解决方案是在创建的对象上创建obj.Qty1 = innerResponse[i].Qty;数组,然后可以根据需要添加任意数量的Qty值。

对于索引,您不再需要使用破折号,ES6中现在有了一个本机的findIndex,因此您可以通过以下方式获取索引:

obj

由于您使用的是ES6,因此可以使用Array.forEach替换for循环以获得更清晰的代码。

在原始函数中使用Qty2Qty的解决方案如下:

const outerIndex = combinedResponse.findIndex(o => o.Location === innerResponse[i].Location && o.OrderNo === innerResponse[i].OrderNo);

这是使用数组而不是命名键的解决方案:

Qty1

希望有帮助:-)

答案 3 :(得分:0)

此解决方案不会更改原始API响应。

let response1 = [{
  Location: 'Boston',
  OrderNo: '406643',
  Qty: '46.1650',
  OrderDate: null,
  Status: null,
}, ];

let response2 = [{
    Location: 'Boston',
    OrderNo: '406643',
    Qty: '22.27',
    OrderDate: '28/11/0018',
    Status: null,
  },
  {
    Location: 'Boston',
    OrderNo: '526209',
    Qty: '21.94',
    OrderDate: '01/03/0019',
    Status: null,
  },
  {
    Location: 'Boston',
    OrderNo: '526209',
    Qty: '65.36',
    OrderDate: '01/03/0019',
    Status: null,
  },
];

const combinedResponse = response2.map(o => {
  const found = response1.find(v => v.Location === o.Location && v.OrderNo === o.OrderNo) || {};
  const clone = Object.assign({}, o);
  clone.Qty2 = clone.Qty || '0';
  clone.Qty1 = found.Qty || '0';
  delete clone.Qty;
  return clone;
});

console.log(combinedResponse);