sql >> Databasteknik >  >> NoSQL >> Redis

Använd redis för att skapa en realtidschatt med socket.io och NodeJs

Redis är mer än nyckel-värde butik.

Så du vill ha följande:

  • chattmeddelanden,
  • diskussioner för två personer,
  • du nämnde inte tidsbegränsningar, så låt oss anta att du arkiverar meddelanden efter ett tag,
  • du säger inte heller om du vill ha separata "trådar" mellan två personer, som forum eller kontinuerliga meddelanden, som facebook. Jag antar kontinuerligt.

För varje användare måste du lagra meddelanden han skickar. Låt oss säga APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID> . Vi lägger till användar-ID här så att vi enkelt kan hämta alla meddelanden som skickats av en enskild användare.

Och för varje två användare måste du spåra deras konversationer. Som nyckel kan du helt enkelt använda deras användar-ID APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID> . För att se till att du alltid får samma delade konversation för de två användarna kan du sortera deras ID alfabetiskt, så att användare 132 och 145 båda har 132:145 som konversationsnyckel

Så vad ska man lagra i "samtal"? Låt oss använda en lista:[messageKey, messageKey, messageKey] .

Ok, men vad är nu meddelandenyckeln? Kombination av användar-ID ovan och ett meddelande-ID (så att vi kan få det faktiska meddelandet).

Så i princip behöver du två saker:

  1. Lagra meddelandet och ge det ett ID
  2. Lagra en referens till detta meddelande till den relevanta konversationen.

Med nod och standard Redis/hiredis-klient skulle detta vara något liknande (jag hoppar över de uppenbara felkontrollerna etc, och jag skriver ES6. Om du inte kan läsa ES6 än, klistra bara in den 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 är det grovt och oprövat, men det är kärnan i hur du kan göra det här.



  1. Mongodb snabbkorrigering KB2731284

  2. Predis med laravel 5.5 Inga anslutningar tillgängliga i poolen i Aggregate/RedisCluster.php:337

  3. Infoga ett värde vid en specifik position i en array i MongoDB

  4. Mongoose.js skapar flera anslutningar till MongoDB från ett connect()-anrop