3

私はモンゴとノードが初めてです。現在、Mongoskin と Bluebird を使用して db 接続とクエリを処理しています (ここで提案されているように: https://stackoverflow.com/a/23687958/2701348 )。

ユーザー、バインダー、カードの 3 つのコレクションがあります。

Binders コレクションには、各ユーザーのカードに関する情報が含まれています。バインダー内の各ドキュメントには、次のプロパティがあります。

User Id <--- that refers to the User owning the Card
Card Code <--- that refers to a Card
Count <--- that refers to the number of cards owned by the User

カードが変更されると、すべてのユーザー バインダーに対して変更されるように、別の Cards コレクションを用意することを好みます。

ここで、次のような特定のユーザーの配列を取得します。

[{card: {card document}, count: 4}, ...]

次の問題があります。

  • すべての非同期dbコールバックが呼び出された後、db接続を閉じる必要があります
  • カード配列は、最後の db.collection('cards').find が結果を返した後に返される必要があります

次のコードが間違っていることはわかっていますが、議論の出発点になる可能性があります。

var getAllBinderCards = function(req, res){
    var db = req.db;
    var userId = req.userId;

    var promiseBinders = db.collection('binders').find({userId: userId}).toArrayAsync();

    promiseBinders.then(function(binderCards) {
        if (binderCards) {
            var promiseCards;
            //console.log("------ binderCards: ", binderCards);
            var cards = [];
            for (var i = 0; i < binderCards.length; i++) {
                var binderCard = binderCards[i];

                promiseCards = db.collection('cards').find({Code: binderCard.Code}).toArrayAsync();
                promiseCards.then(function(cardsDB){
                    if(cardsDB){
                        //console.log("Cards found: ",binderCard.Code, cardsDB);
                        for (var i = 0; i < cardsDB.length; i++) {
                            cardsDB[i].count = binderCard.count;
                        };
                        cards.concat(cardsDB);
                    }
                }); 
            }

            promiseCards.then(function(){
                db.close();
                console.log("Binder Cards: " , cards);
                res.json(cards);
            });
        }
    });
}

配列全体を送り返し、データベース接続を閉じるために、約束された非同期呼び出しを正しく処理する方法を見つけようとして苦労しています。

for ループの前に promise を構築し、それを使用して Cards promise のクエリをチェーンし、最後に db.close() および res.json(cards) ステートメントをチェーンする必要があると思います。

[編集] おそらく最も簡単な解決策は、単一のdb.collection('cards').find({Code: {$in: [bindersCodeArray] }}).toArrayAsync();内で単純に $in フィルターを使用することです。forループを避けます:

var getAllBinderCards = function(req, res){
    var db = req.db;
    var userId = req.userId;

    var promiseBinders = db.collection('binders').find({userId: userId}).toArrayAsync();

    promiseBinders.then(function(binderCards) {
        if (binderCards) {
            var binderCodes = binderCards.map(function(element){
                return element.Code;
            });
            var promiseCards = db.collection('cards').find({Code: {$in: binderCodes} }).toArrayAsync();
            promiseCards.then(function(cards){

                var bindersDictionary = {};

                for (var i = 0; i < binderCards.length; i++) {
                    bindersDictionary[binderCards[i].Code] = binderCards[i].count;
                };

                for (var i = 0; i < cards.length; i++) {
                    cards[i].count = bindersDictionary[cards[i].Code];
                };

                db.close();
                console.log("Binder Cards: " , cards);
                res.json(cards);
            });

        }
    });
}

Promise を使用してこのなぞなぞを解決するエレガントな方法があるかどうか、まだ興味があります。

4

1 に答える 1