Redis е нещо повече от магазин ключ-стойност.
Значи искате следното:
- чат съобщения,
- дискусии от двама души,
- не споменахте времеви ограничения, така че да предположим, че архивирате съобщения след известно време,
- също така не казвате дали искате отделни „нишки“ между двама души, като форуми или непрекъснати съобщения, като facebook. Предполагам непрекъснато.
За всеки потребител трябва да съхранявате съобщенията, които той изпраща. Да кажем APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID>
. Тук добавяме userId, за да можем лесно да извличаме всички съобщения, изпратени от един потребител.
И за всеки двама потребители трябва да проследявате разговорите им. Като ключ можете просто да използвате техните потребителски идентификатори APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID>
. За да сте сигурни, че винаги получавате един и същ споделен разговор за двамата потребители, можете да сортирате техните идентификационни номера по азбучен ред, така че потребителите 132 и 145 ще имат 132:145 като ключ за разговор
И така, какво да съхранявате в „разговори“? Нека използваме списък:[messageKey, messageKey, messageKey]
.
Добре, но какво е сега messageKey? Комбинация от userId по-горе и messageId (за да можем да получим действителното съобщение).
Така че по принцип имате нужда от две неща:
- Съхранете съобщението и му дайте идентификатор
- Съхранете препратка към това съобщение в съответния разговор.
С възел и стандартен redis/hiredis клиент това би било нещо като (ще пропусна проверките за очевидна грешка и т.н. и ще напиша ES6. Ако все още не можете да прочетете ES6, просто го поставете в 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);
});
});
}
Това е грубо и непроверено, но това е същността на това как можете да направите това.