最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - JS: How can I mergejoin arrays of objects by a certain keyproperty? - Stack Overflow

programmeradmin5浏览0评论

What is the best way to join data in JavaScript? Are there libraries like e.g. Pandas in Python or is iteration the way to go? I have two arrays with different objects inside. The list orders contains information about orders in general and the list ordersPayed contains the information whether an order was already payed + the amount etc.

const orders = [
{
    orderId: 1,
    orderDate: '2018-01-01',
    orderAmount: 100
},
{
    orderId: 2,
    orderDate: '2018-02-01',
    orderAmount: 100
},
{
    orderId: 3,
    orderDate: '2018-03-01',
    orderAmount: 100
},
{
    orderId: 4,
    orderDate: '2018-03-01',
    orderAmount: 100
}];
    
const ordersPayed = [
{
    orderId: 1,
    payedAmount: 90,
    debitorName: 'abc'
},
{
    orderId: 3,
    payedAmount: 80,
    debitorName: 'abc'
},
{
    orderId: 6,
    payedAmount: 90,
    debitorName: 'abc'
}];

let newOrderList = [];
    
for (i = 0; i < orders.length; i++) {
    for (j = 0; j < ordersPayed.length; j++) {
        if (orders[i].orderId == ordersPayed[j].orderId) {
            newOrderList.push(orders[i].orderId);
            newOrderList.push(orders[i].orderDate);
            newOrderList.push(orders[i].orderAmount);
            newOrderList.push(ordersPayed[j].payedAmount);
            newOrderList.push(ordersPayed[j].debitorName);
        }
        else if (j == (ordersPayed.length-1)) {
            newOrderList.push(orders[i].orderId);
            newOrderList.push(orders[i].orderDate);
            newOrderList.push(orders[i].orderAmount);
            newOrderList.push('not_payed_yet');
            newOrderList.push('not_known_yet');
        }
    }
}
    
console.log(newOrderList);

What is the best way to join data in JavaScript? Are there libraries like e.g. Pandas in Python or is iteration the way to go? I have two arrays with different objects inside. The list orders contains information about orders in general and the list ordersPayed contains the information whether an order was already payed + the amount etc.

const orders = [
{
    orderId: 1,
    orderDate: '2018-01-01',
    orderAmount: 100
},
{
    orderId: 2,
    orderDate: '2018-02-01',
    orderAmount: 100
},
{
    orderId: 3,
    orderDate: '2018-03-01',
    orderAmount: 100
},
{
    orderId: 4,
    orderDate: '2018-03-01',
    orderAmount: 100
}];
    
const ordersPayed = [
{
    orderId: 1,
    payedAmount: 90,
    debitorName: 'abc'
},
{
    orderId: 3,
    payedAmount: 80,
    debitorName: 'abc'
},
{
    orderId: 6,
    payedAmount: 90,
    debitorName: 'abc'
}];

let newOrderList = [];
    
for (i = 0; i < orders.length; i++) {
    for (j = 0; j < ordersPayed.length; j++) {
        if (orders[i].orderId == ordersPayed[j].orderId) {
            newOrderList.push(orders[i].orderId);
            newOrderList.push(orders[i].orderDate);
            newOrderList.push(orders[i].orderAmount);
            newOrderList.push(ordersPayed[j].payedAmount);
            newOrderList.push(ordersPayed[j].debitorName);
        }
        else if (j == (ordersPayed.length-1)) {
            newOrderList.push(orders[i].orderId);
            newOrderList.push(orders[i].orderDate);
            newOrderList.push(orders[i].orderAmount);
            newOrderList.push('not_payed_yet');
            newOrderList.push('not_known_yet');
        }
    }
}
    
console.log(newOrderList);

The matching is done by the key orderId. At the end I want to have a new list with all orders + the corresponding info whether they were already payed or not.

The code above is my approach to go, but I don't know if this is good for performance reasons and whether there are more pitfalls. So I thought of a matching library or something similar.

Unfortunately this doesn't work 100% correctly. The result should look something like this:

[{
    orderId: 1,
    orderDate: '2018-01-01',
    orderAmount: 100,
    payedAmount: 90
},
{
    orderId: 2,
    orderDate: '2018-02-01',
    orderAmount: 100,
    payedAmount: 'not_payed_yet'
},
{
    orderId: 3,
    orderDate: '2018-03-01',
    orderAmount: 100,
    payedAmount: 80
},
{
    orderId: 4,
    orderDate: '2018-03-01',
    orderAmount: 100,
    payedAmount: 'not_payed_yet'
}]

Anybody got any tips?

Share Improve this question edited Nov 4, 2021 at 5:27 sunwarr10r asked Sep 16, 2018 at 12:28 sunwarr10rsunwarr10r 4,7979 gold badges64 silver badges119 bronze badges 3
  • Where is the data from? If it is from a database, you could solve this with a simple join on the server side. – Krisztián Balla Commented Sep 16, 2018 at 12:33
  • asking for llibrary is ot. please add the wanted result as well, beside the problem you are facing. – Nina Scholz Commented Sep 16, 2018 at 12:33
  • 2 Possible duplicate of Inner join two objects javascript – Hasan Fathi Commented Sep 16, 2018 at 13:01
Add a ment  | 

5 Answers 5

Reset to default 6
const newOrderList = orders.map((order, index) => {
   let payedOrder = ordersPayed.find(o => o.orderId === order.orderId);
   return Object.assign({}, order, payedOrder)
});

You can try following solution:

// Returns an array with order objects, which contain all information
let newOrderList = orders.map((order, index) => {
    let payedOrder = ordersPayed.find(o => o.orderId === order.orderId);

    // Returns a new object to not manipulate the original one
    return {
        orderId: order.orderId,
        orderDate: order.orderDate, 
        orderAmount: order.orderAmount, 
        payedAmount: payedOrder ? payedOrder.payedAmount : 'not_payed_yet', 
        debitorName: payedOrder ? payedOrder.debitorName: 'not_known_yet'
    }
});

Using lodash and ES6 arrow notation the solution can bee quite short:

// Array of Javascript Objects 1:
const orders = [{
    orderId: 1,
    orderDate: '2018-01-01',
    orderAmount: 100
  },
  {
    orderId: 2,
    orderDate: '2018-02-01',
    orderAmount: 100
  },
  {
    orderId: 3,
    orderDate: '2018-03-01',
    orderAmount: 100
  },
  {
    orderId: 4,
    orderDate: '2018-03-01',
    orderAmount: 100
  }
];

// Array of Javascript Objects 2:
const ordersPayed = [{
    orderId: 1,
    payedAmount: 90,
    debitorName: 'abc'
  },
  {
    orderId: 3,
    payedAmount: 80,
    debitorName: 'abc'
  },
  {
    orderId: 6,
    payedAmount: 90,
    debitorName: 'abc'
  }
];


var merged = _.merge(_.keyBy(orders, 'orderId'), _.keyBy(ordersPayed, 'orderId'));

const newArr = _.map(merged, o => _.assign({
  "payedAmount": "not_payed_yet",
  "debitorName": "not_known_yet"
}, o));

var result = _.values(newArr);

console.log(result);
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}
<script src="https://cdn.jsdelivr/npm/[email protected]/lodash.min.js"></script>

For your problem, I would use the Array.reduce with Array.find:

const newOrderList = orders.reduce((acc, order) => {
    const { orderId } = order;
    const orderPayed =  ordersPayed.find((orderPayed) => orderPayed.orderId === orderId);

    if (orderPayed) {
        return [
            ...acc,
            {
                ...order,
                ...orderPayed,
            }
        ];
    }

    return [
        ...acc,
        {
            ...order,
        },
    ];
}, []);

There is a small error in you code. The else if there is not going to work the way you want, because you will always push a not found entry to the new array, whenever the last match fails. You could try this adjusted version of your code:

const orders = [
{
    orderId: 1,
    orderDate: '2018-01-01',
    orderAmount: 100
},
{
    orderId: 2,
    orderDate: '2018-02-01',
    orderAmount: 100
},
{
    orderId: 3,
    orderDate: '2018-03-01',
    orderAmount: 100
},
{
    orderId: 4,
    orderDate: '2018-03-01',
    orderAmount: 100
}];
    
const ordersPayed = [
{
    orderId: 1,
    payedAmount: 90,
    debitorName: 'abc'
},
{
    orderId: 3,
    payedAmount: 80,
    debitorName: 'abc'
},
{
    orderId: 6,
    payedAmount: 90,
    debitorName: 'abc'
}];

let newOrderList = [];
    
for (i = 0; i < orders.length; i++) {
    let payed = false;
    for (j = 0; j < ordersPayed.length; j++) {
        if (orders[i].orderId == ordersPayed[j].orderId) {
            newOrderList.push({ orderId: orders[i].orderId,
                                orderDate: orders[i].orderDate,
                                orderAmount: orders[i].orderAmount,
                                payedAmount: ordersPayed[j].payedAmount,
                                debitorName: ordersPayed[j].debitorName });
            payed = true;
        }
    }
    if (!payed) {
        newOrderList.push({ orderId: orders[i].orderId,
                            orderDate: orders[i].orderDate,
                            orderAmount: orders[i].orderAmount,
                            payedAmount: 'not_payed_yet',
                            debitorName: 'not_known_yet' });
    }
}
    
console.log(newOrderList);

But keep in mind that this is only going to work if you have a 1:1 relationship between the datasets. Meaning if you can have multiple entries in ordersPayed for an entry in orders, the result is also going to have multiple entries for those orders.

发布评论

评论列表(0)

  1. 暂无评论