I'm struggling with merging two arrays of objects (fetched from blockchain data) into a new array based on object values.
The goal is to get the latest interaction with a user.
A simplified but close representation of the data structure this problem is faced in:
interface MsgSlice {
messageId: string;
messageDataSlice: {
senderId?: string;
receiverId: string;
timestamp: number;
};
};
const latestReceivedMsgs: MsgSlice[] = [
{
messageId: "messageId1",
messageDataSlice: {
senderId: "userId1",
receiverId: "ownerId", // <- always same in that array
timestamp: 101,
},
},
{
messageId: "messageId3",
messageDataSlice: {
senderId: "userId2",
receiverId: "ownerId",
timestamp: 103,
},
},
{
messageId: "messageId5",
messageDataSlice: {
senderId: "userId3",
receiverId: "ownerId",
timestamp: 105,
},
},
];
const latestSentMsgs: MsgSlice[] = [
{
messageId: "messageId2",
messageDataSlice: {
// senderId: "ownerId",
receiverId: "userId1",
timestamp: 102,
},
},
{
messageId: "messageId4",
messageDataSlice: {
receiverId: "userId3",
timestamp: 104,
},
},
];
The desired result should contain the latest messageId either 'sent to' or 'received by' the corresponding user. Something like this:
const latestInteraction = [
{
user: "userId1",
messageId: "messageId2",
timestamp: 102,
},
{
user: "userId2",
messageId: "messageId3",
timestamp: 103,
},
{
user: "userId3",
messageId: "messageId5",
timestamp: 105,
},
]
As a solution I thought of looping over the arrays and per iteration also looping over the other array to compare the senderId
and receiverId
values. If "senderId
is == one of the looped receiverId
s", it could be sent into an interaction
array and then time sorted and filtered. Unfortunately, I couldn't figure out how to get it working. My thinking might be limited here, and there are likely more efficient ways to do it than in my solution concept.
You can use the hash grouping approach, the vanila JS solution
Live Demo:
const latestReceivedMsgs = [{messageId: "messageId1",messageDataSlice: {senderId: "userId1",receiverId: "ownerId", timestamp: 101,},},{messageId: "messageId3",messageDataSlice: {senderId: "userId2",receiverId: "ownerId",timestamp: 103,},},{messageId: "messageId5",messageDataSlice: {senderId: "userId3",receiverId: "ownerId",timestamp: 105,},},];
const latestSentMsgs = [{messageId: "messageId2",messageDataSlice: {receiverId: "userId1",timestamp: 102,},},{messageId: "messageId4",messageDataSlice: {receiverId: "userId3",timestamp: 104,},},];
const grouped = [...latestReceivedMsgs, ...latestSentMsgs]
.reduce((acc, { messageId, messageDataSlice }) => {
const { timestamp, senderId, receiverId } = messageDataSlice;
const user = senderId ?? receiverId;
const msgItem = { user, messageId, timestamp };
if ((acc[user]?.timestamp ?? 0) < timestamp) acc[user] = msgItem;
return acc;
}, {});
const result = Object.values(grouped);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }
UPDATE
Or typescript variant:
interface MsgSlice {
messageId: string;
messageDataSlice: {
senderId?: string;
receiverId?: string;
timestamp: number;
};
};
interface Interaction {
user: string
messageId: string
timestamp: number
};
const latestReceivedMsgs: MsgSlice[] = [{messageId: "messageId1",messageDataSlice: {senderId: "userId1",receiverId: "ownerId", // <- always same in that array},},{messageId: "messageId3",messageDataSlice: {senderId: "userId2",receiverId: "ownerId",timestamp: 103,},},{messageId: "messageId5",messageDataSlice: {senderId: "userId3",receiverId: "ownerId",timestamp: 105,},},];
const latestSentMsgs: MsgSlice[] = [{messageId: "messageId2",messageDataSlice: {receiverId: "userId1",timestamp: 102,},},{messageId: "messageId4",messageDataSlice: {receiverId: "userId3",timestamp: 104,},},];
const grouped = ([...latestReceivedMsgs, ...latestSentMsgs] as MsgSlice[])
.reduce((acc, { messageId, messageDataSlice }) => {
const { timestamp, senderId, receiverId } = messageDataSlice;
const user = senderId ?? receiverId ?? "unindefined";
const msgItem = { user, messageId, timestamp };
if ((acc[user]?.timestamp ?? 0) < timestamp) acc[user] = msgItem
return acc;
}, {} as { [key: Interaction['user']]: Interaction });
const result: Interaction[] = Object.values(grouped);
console.log(result);