I would like to group all messages between 2 people in a group (chat). Doesn`t matter if I am the author or receiver.
Let's say this example code.
const messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]
Imagine, I am user ID = 1, so I would like to get this:
const chats = [
{
chatName: 'Name of user ID 2', messages: [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
]
},
{
chatName: 'Name of user ID 3', messages: [
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]
}
];
How can I achieve this with Lodash?
Not sure about lodash, but you can use plain js - reduce
and map
to get that structure
const messages = [{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } }, { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } }, { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } }, ]; function groupByPair(arr) { return [ ...arr.reduce((a, b) => { let { author, receiver } = b; let s = [author.id, receiver.id].sort().join('-'); a.set(s, a.has(s) ? a.get(s).concat(b) : [b]); return a; }, new Map) ].map(e => ({ chatName: 'Name of user ID ' + e[0].substring(e[0].indexOf('-') + 1), messages: e[1] })); } console.log(groupByPair(messages));
Using either Lodash or Underscore.js:
var grouped = _.groupBy(messages, m => _.sortBy([m.author.id, m.receiver.id]));
var formatted = _.map(grouped, (v, name) => ({ chatname: name, messages: v }));
You could combine those into a single line, but that seems overly dense to my eyes.
I took the liberty of defining a more complex test dataset, to make sure the edge cases were better covered:
var messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
{ id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } },
{ id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } },
{ id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
]
With this data, the code above yields a formatted
of:
[
{ chatname: '1,2',
messages: [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } }
]
},
{ chatname: '1,3', messages: [
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
{ id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
]
},
{ chatname: '3,4', messages: [
{ id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } }
]
}
]
The major difference with your desired output relates to the chatname
values. I did not see how you were naming those, so I stuck with Lodash/Underscore's native groupby
keys.
You can do this with _.groupby
. I filter the array first so that you're only left with messages that involve user 1.
const messages = [ { id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } }, { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } }, { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } }, ]; const filtered = messages.filter((msg) => { return msg.author.id === '1' || msg.receiver.id === '1' }); const groups = _.groupBy(filtered, (msg) => { return msg.author.id === '1' ? msg.receiver.id : msg.author.id }); console.log(groups);
<script src="https://unpkg.com/lodash@4.17.4"></script>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.