2013-06-19 12 views
16

Mam dwie kolekcje mangusty. Pierwszy zapisuje listę miejsc, a drugi odwiedza miejsca. Mój kod węzła przechodzi i próbuje uzyskać listę wizyt w każdym miejscu i zbudować ciąg, który wypisz jako JSON. Pierwsze zapytanie kończy się przed pierwszym uruchomieniem - czy istnieje sposób ich synchronicznego działania?Tworzenie zapytań mongoose.js synchronicznie

+0

Dlaczego nie rozpocząć drugiej kwerendy po pierwszym zakończeniu, jeśli zamówienie ma znaczenie (chociaż nie rozumiem, dlaczego zamówienie ma znaczenie, o ile kod budowania JSON czeka na ich zakończenie?) – WiredPrairie

Odpowiedz

11

Nie ma natywnego synchronicznego api dla zapytań mongodów/mangusty (a twój nie chciałby, aby był praktyczny). Jak wspomina WiredPrarie, powinieneś połączyć zapytania, a drugi zaczyna się po pierwszym uruchomieniu i uruchomieniu wywołania zwrotnego. Oto przykład:

function findVisits(placesQuery,callback){ 
    Places.find(placesQuery).exec(function(err,places){ 
     if (err || !places.length){ 
      console.log('there was a problem'); 
      callback(err, null); 
     }else{ 
      var visitQuery = ... //however you want to filter places 
      Visits.find(visitQuery).exec(function(err2,visits){ 
       if (err2 || !visits.length){ 
        console.log('there was a problem'); 
        callback(err2,null); 
       }else{ 
        callback(null, visits) 
       } 
      }); 
     } 
    }); 
} 
+5

Naprawianie odpowiedzi: Nie ma sposób synchronicznej pracy w węźle. – gustavohenke

+0

'Nie ma natywnego synchronicznego api dla zapytań mongodów/mangusty 'Złe wieści dla mnie, próbowałem uzyskać auto increment do pracy jak w przykładzie mongodb tutaj: http://docs.mongodb.org/manual/tutorial/create -an-auto-inkrementujące-pole/ale 'getNextSequence' nie może być asynchroniczne, ponieważ musi zwracać liczbę. Próba zastosowania tego automatycznego przyrostu w mangurze, ale musi znaleźć jakiś sposób wykonania funkcji synchronicznej: http: // stackoverflow.com/questions/28357965/mongoose-auto-increment – HMR

+2

Nie zgadzam się z komentarzem "(i nie chciałbym, żeby jeden był praktyczny)". To jest dla każdego programisty mieć własne potrzeby. Na przykład. podczas debugowania w konsoli REPL w węźle, znacznie łatwiej byłoby przypisać wyniki linii po linii. Mogę wtedy użyć małej wtyczki, aby to zrobić. –

14

Jeśli używasz node.js następnie u powinny wykorzystywać https://github.com/caolan/async

kiedy trzeba pobierać dane z wielu kolekcjach trzeba wiele razy łańcucha zapytań.

Uczyni to Twój kod złożonym i trudnym do odczytania, bez modułowości. Użyj asynchroniczny stworzyć modułowość użyciu MongoDB i node.js

przykład kodu z mojego projektu:

var async = require('async'); 

var createGlobalGroup = function(socket, data) { 
    async.waterfall(
    [ 
    /** 
    * this function is required to pass data recieved from client 
    * @param {Function} callback To pass data recieved from client 
    */ 

    function(callback) { 
     callback(null, socket, data); 
    }, 
    /** 
    * Step 1: Verify User 
    */ 
    verifyUser, 
    /** 
    * Step 2: Check User Access Rights And Roles 
    */ 
    checkUserAccessRightsAndRoles, 
    /** 
    * Step 3: Create Project 
    */ 
    createNewGlobalGroup], function(err, result) { 
     /** 
     * function to be called when all functions in async array has been called 
     */ 
     console.log('project created ....') 
    }); 
} 
verifyUser = function(socket, data, callback) { 
//do your query 
    /** 
    * call next function in series 
    * provide sufficient input to next function 
    */ 
    callback(null, socket, data, { 
     "isValidUser": true, 
    }); 
} 

checkUserAccessRightsAndRoles = function(socket, data, asyncObj, callback) { 
    //do your query 
    if(condition) { 
     callback(null, socket, data, { 
      roles: result, 
      "isValidUser": asyncObj.isValidUser, 
      "userId": asyncObj.userId, 
     }); 
    } else { 
    //no call back 
    } 
} 

var createNewGlobalGroup = function(socket, data, asyncObj, callback) { 
//wanna stop then no callback 
} 
0

Oto alternatywna metoda wytwarzania pseudo synchronicznych żądań za pomocą MongooseJS. Chodzi o to, aby utworzyć kolejkę zapytań, które należy wykonać. Następnie utwórz funkcję, która jest wywoływana rekurencyjnie, dopóki kolejka nie zostanie wyczerpana. Po wyczerpaniu kolejki rekursja zatrzymuje się, a odpowiedź jest wysyłana z powrotem do pierwotnego żądania. Używam Express Routes, więc cały ten kod jest zamknięty w mojej procedurze obsługi trasy. W tym przypadku HTTP POST.

var express = require('express'); 
var router = express.Router(); 

//POST /auth/create 
router.post('/create', function(req, res) { 
    var queue = [ 
     {"schema": require('..\\models\\people.js'), "query": {username: req.body.username}}, 
     {"schema": require('..\\models\\members.js'), "query": {username: req.body.username}} 
    ], 
    retData = []; 

    var curTask = 0. 


    function recurse() 
    { 
     if(curTask < queue.length){ 
       var task = queue[curTask]; 
       task.schema.findOne(task.query, function(err, data){ 
       retData.push(err || data); 
       curTask++; 
       recurse(); 
      }) 
     }else{ 
      res.json(retData); 
     } 

    } 

    recurse(); 

}); 



module.exports = router; 
2

Do synchronizacji Użyłem obietnicy es6.

var Promise = require('es6-promise').Promise 
    , mongoose = require('mongoose') 
    , Schema = mongoose.Schema; 

// define schemas and models. 
var placeSchema = new Schema({ 
     name: { type: String }, 
     memo: { type: String } 
    }) 
    , Places = mongoose.model('place', placeSchema) 
    , visitSchema = new Schema({ 
     placeName: { type: String }, // foreign key for place. 
     visitor: { type: String }, 
     comment: { type: String } 
    }) 
    , Visits = mongoose.model('visit', visitSchema); 

// query for visits by visitor and place. 
function findVisitsWithPlace(visitor, place) { 
    return new Promise(function (resolve, reject) { 
     Visits.find({ 
      visitor: visitor, 
      placeName: place.name 
     }, function (error, visits) { 
      if (error) { 
       reject(error); 
       return; 
      } 

      // build a result object you want. 
      //() 
      resolve({ 
       place: place, 
       visits: visits 
      }); 
     }); 
    }); 
} 

// functions for node route. 
module.exports = { 
    // - access to "GET /placevisits/?visitor=Visitor-1". 
    get: function (request, response) { 
     var visitor = request.query.visitor; 

     // - to get the places... 
     Places.find({}, function (error, places) { 
      Promise.all(places.map(function (place) { 
       // - run the child queries with parent object... 
       return findVisitsWithPlace(visitor, place); 
      })).then(function (placeAndVisits) { 
       // - and get result. 
       // placeAndVisits have still contain visits empty. 
       // exclude them. 
       var result = []; 
       placeAndVisits.forEach(function (placeandvisit) { 
        if (placeandvisit.visits.length != 0) { 
         result.push(placeandvisit); 
        } 
       }); 
       response.json(result); 
      }); 
     }); 
    } 
}; 

i JSON podąża za mną.

[ 
    { 
     "place": { 
      "_id": "564e58a1dbed862155771d46", 
      "name": "Place-A", 
      "memo": "A memo for Place A." 
     }, 
     "visits": [ 
      { 
       "_id": "564e58cedbed862155771d49", 
       "placeName": "Place-A", 
       "visitor": "Visitor-1", 
       "comment": "A comment for Place A by Visitor-1" 
      }, 
      { 
       "_id": "564e58dcdbed862155771d4a", 
       "placeName": "Place-A", 
       "visitor": "Visitor-1", 
       "comment": "2nd visit. Again comment for Place A by Visitor-1" 
      } 
     ] 
    }, 
    { 
     "place": { 
      "_id": "564e58afdbed862155771d47", 
      "name": "Place-B", 
      "memo": "A memo for Place B." 
     }, 
     "visits": [ 
      { 
       "_id": "564e58ebdbed862155771d4c", 
       "placeName": "Place-B", 
       "visitor": "Visitor-1", 
       "comment": "A comment for Place B by Visitor-1" 
      } 
     ] 
    } 
] 
2

Dziś mangusta wspiera obietnice, więc możesz .then() swoje pytania. Na przykład:

app.get(function (req, res, next) { 
    Users.findOne({ 
    username: req.body.username, 
    password: req.body.password, 
    }).then(user => { 
    if (!user) { 
     res.json({success: false, message: "Username or password incorrect."}); 
     return; 
    } 

    return Notifications.find({ 
     user: user._id 
    }).then(notifications => { 
     res.json({success: true, notifications}); 
    }); 
).catch(error => { 
    //console.error(error); 
    //res.json({success: false, error: error.message}); 
    next(error); 
    }); 
}); 
5

Jeśli używasz 8.x Node można wykorzystać asynchroniczny/Oczekujcie: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

czekają operator wstrzymuje wykonanie funkcji asynchronicznym aż obietnica jest rozwiązany i zwraca wartość. W ten sposób Twój kod będzie wyglądać bardziej synchronicznie:

const query1 = MyModel.find({ name: /john/i }, null, { skip: 10 }); 
const result1 = await query1.exec(); 

const query2 = MyModel.find({ name: /john/i }, null, { skip: 100 }); 
const result2 = await query2.exec(); 

Zapytania będą wykonywane kolejno.

+0

Dzięki za wskazanie mi, że "czekam" - wydaje się, że dobrze jest być prawdą: znacznie szybciej jest pisać i czytać zapytania Mongoose/Mongo. – Shouvik

+0

Należy pamiętać, że nadal trzeba postępować z błędami, będą one zgłaszane jako wyjątki. – vsenko

Powiązane problemy