Redis er mere end nøgleværdibutik.
Så du vil have følgende:
- chatbeskeder,
- diskussioner på to personer,
- du nævnte ikke tidsbegrænsninger, så lad os antage, at du arkiverer beskeder efter et stykke tid,
- du siger heller ikke, om du vil have separate "tråde" mellem to personer, f.eks. fora eller løbende beskeder, f.eks. facebook. Jeg antager kontinuerlig.
For hver bruger skal du gemme beskeder, han sender. Lad os sige APP_NAMESPACE:MESSAGES:
. Vi tilføjer bruger-id her, så vi nemt kan hente alle beskeder sendt af en enkelt bruger.
Og for hver to brugere skal du spore deres samtaler. Som nøgle kan du blot bruge deres bruger-id APP_NAMESPACE:CONVERSATIONS:
Så hvad skal man gemme i "samtaler"? Lad os bruge en liste:[messageKey, messageKey, messageKey]
.
Ok, men hvad er nu messageKey? Kombination af userId ovenfor og et messageId (så vi kan få den faktiske besked).
Så dybest set har du brug for to ting:
- Gem beskeden, og giv den et ID
- Gem en reference til denne besked til den relevante samtale.
Med node og standard redis/hiredis-klient ville dette være noget lignende (jeg springer de åbenlyse fejl osv. over, og jeg skriver ES6. Hvis du ikke kan læse ES6 endnu, skal du bare indsætte det på 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);
});
});
}
Nu er det groft og uafprøvet, men det er kernen i, hvordan du kan gøre dette.