2017-10-10 1 views
0

so habe ich zwei Mongodb-Modell, Konto und die Gespräche. Jeder Account enthält ein Lager mit allen Gesprächen, mit wem und einer ID der Konversation.Verschachtelte asynchrone Abfrage Rückruf in Mongoose

Ich versuche eine Seite zu erstellen, die facebook Messenger ähnelt (Konversationsliste auf der linken Seite, Chat auf der rechten Seite).


Problem

Der Code hängt mit einem Promise <Pending> Fehler innerhalb async des Chat. Ich bin nicht der beste Programmierer und ich verstehe nicht, was es von mir erwartet. Es klingt wie es auf verschachtelte Abfragen oder so etwas warten müsste?


-Code

router.get('/chat/:id', function(req, res) { 
    if (req.user == undefined) { 
    return res.redirect('/'); 
    } 
    else { 
    async.parallel({ 
     conversations: function (err, users){ 
     Account.find({'_id': {$ne: req.user._id}}).exec(err, users) 
     }, 
     chat: function (err,talk){ 
      Account.find({'_id': req.user._id, 'conversations.with': req.params.id}).exec(function(err, talk){ 
       //if conversation ID doesn't exist, create. 
       if(!talk.length){ 
       console.log(err + " No convo with ParamsId exists: " + req.params.id); 
       var newConvo = new Conversation({ 
        owners  : [req.user._id, req.params.id], 
        created_at : Date.now() 
       }); 
       newConvo.save(function(err, convo){ 
        //push conversation ID to both users 
        async.parallel({ 
        modelAFind: function (A){ 
         Account.findByIdAndUpdate(req.user._id, {$push: {'conversations': {'with':req.params.id, 'conversation': convo._id}}}, {safe:true, upsert: true, new : true}).exec(A) 
        }, 
        modelBFind: function (B){ 
         Account.findByIdAndUpdate(req.params.id, {$push: {'conversations': {'with':req.user._id, 'conversation': convo._id}}}, {safe:true, upsert: true, new : true}).exec(B) 
        } 
        }), 
        Conversation.findOne({'owners': {"$all":[req.user._id, req.params.id]}}).populate('owners messages.from').exec(talk); 
       }); 
      } 
      else if (err){console.log(err)} 
      //else if conversation ID exists 
      else { 
       // CODE HANGS HERE!! 
       Conversation.findOne({'owners': {"$all":[req.user._id, req.params.id]}}).populate('owners messages.from').exec(talk); 
      } 
      }); 
     }, 
    }, 
    function(err, result,next){ 
     var ret = result.conversations; 
     console.log(result); 
     ret.dataB = result.chat; 
     res.render('chat', { 
     user: req.user, 
     users: ret, 
     profile : req.params.id, 
     title : req.params.id + 'とチャット', 
     conversationId: ret.dataB 
     }); 
    }); 
    } 
}); 

Wie kann ich erfolgreich die Daten von Conversation.findOne get()?

Vielen Dank!

Antwort

0

Ich glaube, das Problem ist hier:

Sie den Rückruf von async.parallel bereitgestellt nennen, wie talk, dann nennen Sie auch das Ergebnis der Account.find, talk auch.

chat: function (err,talk){ 
     Account.find({'_id': req.user._id, 'conversations.with': req.params.id}).exec(function(err, talk){ 

Dann sehe ich später Sie versuchen, den Rückruf zu übergeben, mit dem Namen talk:

Conversation.findOne({'owners': {"$all":[req.user._id, req.params.id]}}).populate('owners messages.from').exec(talk); 

Aber da diese talk Variable durch das Ergebnis der früheren Account.find Schatten gestellt wird.

So async.parallel Rückruf wird nie aufgerufen, so wird es nie beendet werden.

Um es zu beheben Ich schlage vor, folgen Sie den async und node.js-Modul in allgemeinen Konventionen, nennen Sie es so etwas wie callback oder cb.

Sie also diese Zeile ändern:

chat: function (err,cb){ 

Und es später diese passieren:

Conversation.findOne({'owners': {"$all":[req.user._id, req.params.id]}}).populate('owners messages.from').exec(cb); 

Wenn Sie Knoten 7.5.0 oder höher verwenden, oder bereit, etwas wie Babel zu verwenden, Dann schlage ich vor, die neue Funktion "Warten/Asynchrones JavaScript" zu verwenden. Ich Ihren Code, um es neu geschrieben und es wäre viel leichter, sauberer zu halten, leichter zu verstehen sein, schwieriger, Fehler zu machen:

router.get('/chat/:id', async function(req, res) { 
    if (req.user == undefined) { 
    return res.redirect('/'); 
    } 

    // We haven't called await on this promise yet, so it will be running in 
    // parallel with the other stuff bellow 
    const conversationsPromise = Account.find({'_id': {$ne: req.user._id}}).exec(); 

    const talk = await Account.find({'_id': req.user._id, 'conversations.with': req.params.id}).exec(); 

    let conversation; 

    if(!talk.length){ 
    console.log(err + " No convo with ParamsId exists: " + req.params.id); 
    var newConvo = new Conversation({ 
     owners  : [req.user._id, req.params.id], 
     created_at : Date.now() 
    }); 

    // Await both promises in parallel 
    await Promise.all([ 
     Account.findByIdAndUpdate(req.user._id, {$push: {'conversations': {'with':req.params.id, 'conversation': convo._id}}}, {safe:true, upsert: true, new : true}).exec(), 
     Account.findByIdAndUpdate(req.params.id, {$push: {'conversations': {'with':req.user._id, 'conversation': convo._id}}}, {safe:true, upsert: true, new : true}).exec(), 
    ]); 

    conversation = await Conversation.findOne({'owners': {"$all":[req.user._id, req.params.id]}}).populate('owners messages.from').exec(); 
    } 
    else if (err){console.log(err)} 
    //else if conversation ID exists 
    else { 
    conversation = await Conversation.findOne({'owners': {"$all":[req.user._id, req.params.id]}}).populate('owners messages.from').exec(); 
    } 

    var ret = await conversationsPromise; 

    console.log({ 
    chat: conversation, 
    conversations: ret, 
    }); 
    ret.dataB = conversation; 
    res.render('chat', { 
    user: req.user, 
    users: ret, 
    profile : req.params.id, 
    title : req.params.id + 'とチャット', 
    conversationId: ret.dataB 
    }); 
}); 
+0

Das jetzt viel schöner ist, sie danken Sie Ihre Erklärung war klar, – y4my4m