Redis is meer dan een key-value store.
Dus je wilt het volgende:
- chatberichten,
- discussies tussen twee personen,
- je hebt geen tijdsdruk genoemd, dus laten we aannemen dat je berichten na een tijdje archiveert,
- je zegt ook niet of je aparte "threads" tussen twee mensen wilt, zoals forums of doorlopende berichten, zoals Facebook. Ik ga uit van continu.
Voor elke gebruiker moet je berichten opslaan die hij verzendt. Laten we zeggen APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID>
. We voegen hier userId toe zodat we gemakkelijk alle berichten kunnen terugvinden die door een enkele gebruiker zijn verzonden.
En voor elke twee gebruikers moet u hun gesprekken volgen. Als sleutel kunt u eenvoudig hun gebruikers-ID's gebruiken APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID>
. Om ervoor te zorgen dat u altijd hetzelfde, gedeelde gesprek voor de twee gebruikers krijgt, kunt u hun id's alfabetisch sorteren, zodat gebruikers 132 en 145 beide 132:145 als gesprekssleutel hebben
Dus wat op te slaan in "gesprekken"? Laten we een lijst gebruiken:[messageKey, messageKey, messageKey]
.
Ok, maar wat is nu de messageKey? Combinatie van userId hierboven en een messageId (zodat we het eigenlijke bericht kunnen krijgen).
Dus eigenlijk heb je twee dingen nodig:
- Bewaar het bericht en geef het een ID
- Bewaar een verwijzing naar dit bericht naar het relevante gesprek.
Met node en standaard redis/hiredis-client zou dit zoiets zijn als (ik sla de voor de hand liggende foutcontroles over, en ik zal ES6 schrijven. Als je ES6 nog niet kunt lezen, plak het dan gewoon in babel):
// assuming the init connects to redis and exports a redisClient
import redisClient from './redis-init';
import uuid from `node-uuid`;
export function storeMessage(userId, toUserId, message) {
return new Promise(function(resolve, reject) {
// give it an id.
let messageId = uuid.v4(); // gets us a random uid.
let messageKey = `${userId}:${messageId}`;
let key = `MY_APP:MESSAGES:${messageKey}`;
client.hmset(key, [
"message", message,
"timestamp", new Date(),
"toUserId", toUserId
], function(err) {
if (err) { return reject(err); }
// Now we stored the message. But we also want to store a reference to the messageKey
let convoKey = `MY_APP:CONVERSATIONS:${userId}-${toUserId}`;
client.lpush(convoKey, messageKey, function(err) {
if (err) { return reject(err); }
return resolve();
});
});
});
}
// We also need to retreive the messages for the users.
export function getConversation(userId, otherUserId, page = 1, limit = 10) {
return new Promise(function(resolve, reject) {
let [userId1, userId2] = [userId, otherUserId].sort();
let convoKey = `MY_APP:CONVERSATIONS:${userId1}-${userId2}`;
// lets sort out paging stuff.
let start = (page - 1) * limit; // we're zero-based here.
let stop = page * limit - 1;
client.lrange(convoKey, start, stop, function(err, messageKeys) {
if (err) { return reject(err); }
// we have message keys, now get all messages.
let keys = messageKeys.map(key => `MY_APP:MESSAGES:${key}`);
let promises = keys.map(key => getMessage(key));
Promise.all(promises)
.then(function(messages) {
// now we have them. We can sort them too
return resolve(messages.sort((m1, m2) => m1.timestamp - m2.timestamp));
})
.catch(reject);
});
});
}
// we also need the getMessage here as a promise. We could also have used some Promisify implementation but hey.
export function getMessage(key) {
return new Promise(function(resolve, reject) {
client.hgetall(key, function(err, message) {
if (err) { return reject(err); }
resolve(message);
});
});
}
Dat is grof en niet getest, maar dat is de essentie van hoe je dit kunt doen.