2011-08-11 13 views
1

node.js + cradleとcouchdbを使用してメッセージングシステムに取り組んでいます。CouchDB、Node.js、Cradle - 返されたデータに基づいてデータを取得する方法

ユーザーが自分のメッセージのリストをプルすると、そのメッセージを送信したユーザーのオンラインステータスを取得する必要があります。オンライン状態は、登録ユーザごとにユーザ文書に格納され、メッセージ情報は別の文書に保存されます。ここで

は私が必要なものを行うために管理することができる唯一の方法であるが、その非常に非効率的

privatemessages /メッセージ受信者のすべてのキー=ユーザ名

db.view('privatemessages/all', {"key":username}, function (err, res) { 
    res.forEach(function (rowA) { 
     db.view('users/all', {"key":rowA.username}, function (err, res) { 
      res.forEach(function (row) { 
       result.push({onlinestatus:row.onlinestatus, messagedata: rowA}); 
      }); 
     }); 
    }); 

    response.end(JSON.stringify(result)); 
}); 

誰かが私言うことができますこれを行う正しい方法ですか?

あなたは

答えて

1

ユーザーステータスがまだDBから取得されていないときに応答を呼び出すため、コードが空の結果を返す可能性があります。他の問題は、同じユーザーから複数のメッセージを受信した場合、彼のステータスの呼び出しが重複している可能性があるということです。以下は、ユーザーからの重複を避けてDBからメッセージを取り出し、その状態を取得する機能です。

function getMessages(username, callback) { 
    // this would be "buffer" for senders of the messages 
    var users = {}; 
    // variable for a number of total users I have - it would be used to determine 
    // the callback call because this function is doing async jobs 
    var usersCount = 0; 
    // helpers vars 
    var i = 0, user, item; 

    // get all the messages which recipient is "username" 
    db.view('privatemessages/all', {"key":username}, function (errA, resA) { 
     // for each of the message 
     resA.forEach(function (rowA) { 
      user = users[rowA.username]; 
      // if user doesn't exists - add him to users list with current message 
      // else - add current message to existing user 
      if(!user) { 
       users[rowA.username] = { 
        // I guess this is the name of the sender 
        name: rowA.username, 
        // here will come his current status later 
        status: "", 
        // in this case I may only need content, so there is probably 
        // no need to insert whole message to array 
        messages: [rowA] 
       }; 
       usersCount++; 
      } else { 
       user.messages.push(rowA); 
      } 
     }); 

     // I should have all the senders with their messages 
     // and now I need to get their statuses 
     for(item in users) { 
      // assuming that user documents have keys based on their names 
      db.get(item, function(err, doc) { 
       i++; 
       // assign user status 
       users[item].status = doc.onlineStatus; 
       // when I finally fetched status of the last user, it's time to 
       // execute callback and rerutn my results 
       if(i === usersCount) { 
        callback(users); 
       } 
      }); 
     } 
    }); 
} 

... 

getMessages(username, function(result) { 
    response.end(JSON.stringify(result)); 
}); 

CouchDBのは、それが各更新の後、まったく新しいドキュメントバージョンを作成するため、既存の文書を頻繁に更新して注意しなければならない大きな文書データベースですが(これはそれのために高可用性を実現するために使用されるMVCCモデルだされ、データ耐久性)。この動作の結果、より多くのディスク容量が消費されます(より多くのデータ/更新、さらに必要なディスク容量 - example)。したがって、それを監視し、それに応じてデータベース消費を実行する必要があります。

+0

応答のおかげで、これは私のために多くをクリアしました。とにかく、それぞれのユニークユーザーのデータを取得するのではなく、元の呼び出しでユーザーデータを含むドキュメントをcouchdbに生成させる方法はありますか? – Brian

+0

あなたのメッセージビューにユーザーデータの一部を含めることができます(おそらくreduceまたは[照合照合](http://wiki.apache.org/couchdb/View_collat​​ion))のどちらかを使用することもできますが、私はそうではありません元のユーザー文書が変更された場合にそれらのデータが更新されるかどうか確認してください。私はおそらく各ユニークユーザーのためのスタンドアロンのクエリにとどまるでしょう。速度が必要な場合は、CouchDBとRedisを組み合わせることができます。これは、速度と信頼性の高いデータ永続性の非常に優れた組み合わせです。 – yojimbo87

+0

もう一度おねがいしますが、私はあなたの方法がうまくいくと思っています。私はもう1つの問題がありますが、データを取得する前に上記のコードがコールバックを完了するように思われますが、これは正しいですか? – Brian

1

私はあなたのシステムがmemcachedのようなメモリ内のハッシュマップを使用することができると思いますありがとうございました。それぞれのユーザーステータスエントリは、期限が過ぎると期限切れになります。 マッピングは です[ユーザ - > lasttimeseen]

ハッシュマップにユーザが含まれている場合、ユーザはオンラインです。 いくつかの特定のアクションでは、最新のものをリフレッシュします。

その後、毎回全世界にpingを実行する代わりに、マップ自体を照会して結果を返すだけです。

0

私はこの発表を思い出しています:

Databases Suck for Messaging

そしてティム・オライリーからの引用:45000人のユーザーのための

「月曜日のFriendFeedのポーリングFlickrで約300万回、 6K人だけがログインしていました。アーキテクチュアの不一致。

他の回答で指摘されているように、CouchDBのアップデートは高価であり、可能であれば避けてください。このデータを永続化する必要はないでしょう。キャッシュまたはメッセージングシステムは、よりエレガントで効率的に問題を解決する可能性があります。

関連する問題