Redis является более ключ-значение магазина.
Итак, вы хотите следующее:
- сообщений чата,
- дискуссии двух человек,
- вы не говоря уже о временных ограничений, так что давайте предположим, что вы архивировать сообщения через некоторое время,
- вы также не говорите, хотите ли вы отдельные «потоки» между двумя людьми, например форумы или непрерывные сообщения, например, facebook. Я предполагаю, что он будет непрерывным.
Для каждого пользователя вы должны хранить отправленные им сообщения. Скажем, APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID>
. Мы добавляем здесь userId, чтобы мы могли легко восстановить все сообщения, отправленные одним пользователем.
И для каждого двух пользователей вам необходимо отслеживать их разговоры. В качестве ключа вы можете просто использовать свои идентификаторы пользователей APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID>
. Чтобы убедиться, что вы всегда получаете то же самое, общий разговор для двух пользователей, вы можете сортировать их идентификаторы по алфавиту, так что пользователи 132 и 145 будут иметь 132: 145 как ключ разговора
Итак, что хранить в «разговорах», ? Давайте воспользуемся списком: [messageKey, messageKey, messageKey]
.
Хорошо, но что теперь представляет сообщение? Комбинация userId выше и messageId (чтобы мы могли получить фактическое сообщение).
Так в основном, вам нужно две вещи:
- сохранить сообщение и дать ему ID
- сохранить ссылку на это сообщение на соответствующий разговор.
с узлом и стандартным Redis/hiredis клиентом это будет somehting как (я пропущу очевидные ошибки и т.д. проверки, и я напишу 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);
});
});
}
Теперь это грубо и непроверено, но это суть того, как вы можете это сделать.
Я использую redis и socket.io, потому что мой проект действительно работает на NodeJs, но спасибо за ваше предложение – leodev