1

私は、node.js + クレードルとカウチデータベースを使用してメッセージング システムに取り組んでいます。

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

これが私が必要とすることを管理できる唯一の方法ですが、非常に非効率的です

privatemessages/all key = メッセージ受信者のユーザー名

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));
});

誰かがこれを行う正しい方法を教えてもらえますか?

ありがとうございました

4

3 に答える 3

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モデルのためです)。この動作の結果として、ディスク容量の消費が増加します (より多くのデータ/更新、より多くのディスク容量が必要 -)。そのため、それを監視し、それに応じてデータベースの消費を実行する必要があります。

于 2011-08-11T09:21:50.903 に答える
1

あなたのシステムは、memcached のようなメモリ内ハッシュマップを使用できると思います。各ユーザー ステータス エントリは、制限時間後に失効します。マッピングは [user -> lasttimeseen] になります。

ハッシュマップにユーザーが含まれている場合、ユーザーはオンラインです。一部の特定のアクションで、最後に表示された時間を更新します。

次に、毎回全世界に ping を送信する代わりに、マップ自体にクエリを実行して結果を返します。

于 2011-08-11T08:00:03.333 に答える
0

私はこのプレゼンテーションを思い出しました:

メッセージングのために吸われるデータベース

そして、ティム・オライリーからの引用:

「月曜日に、friendfeedは45000人のユーザーに対して約300万回flickrをポーリングしましたが、そのうち6Kだけがログインしていました。アーキテクチャの不一致。」

他の回答で指摘されているように、CouchDBでの更新は費用がかかるため、可能であれば回避する必要があり、このデータを永続化する必要はおそらくありません。キャッシュまたはメッセージングシステムは、問題をよりエレガントかつ効率的に解決する可能性があります。

于 2011-08-12T05:07:43.527 に答える