it-swarm.com.de

Das Ausführen von mongoose.js-Abfragen wird synchron ausgeführt

Ich habe zwei Mungosammlungen. Der erste speichert eine Liste der Orte, der zweite ist der Besuch der Orte. Mein Knotencode wird durchlaufen und versucht, die Liste der Besuche an jedem Ort abzurufen und eine Zeichenfolge zu erstellen, die ich als JSON ausgegeben habe. Die erste Abfrage wird abgeschlossen, bevor die zweite überhaupt startet. Gibt es eine Möglichkeit, sie synchron laufen zu lassen?

19
AlexKinsella

Wenn Sie node.js verwenden, sollten Sie https://github.com/caolan/async verwenden.

wenn Sie Daten aus mehreren Sammlungen abrufen müssen, müssen Sie Ihre Abfragen mehrmals verketten.

Dies macht Ihren Code komplex und schwer lesbar und keine Modularität. Verwenden Sie async zum Erstellen von Modularität mit mongodb und node.js

Beispielcode aus meinem Projekt:

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
}
15
Harpreet Singh

Es gibt keine native synchrone API für mongodb/mongoose-Abfragen (und dies ist in der Praxis nicht wünschenswert). Wie WiredPrarie erwähnt, sollten Sie die Abfragen verketten, wobei die zweite nach dem ersten Abschluss beginnt und einen Rückruf ausführt. Hier ist ein Beispiel:

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)
                }
            });
        }
    });
}
11
mr.freeze

Wenn Sie Knoten 8.x verwenden, können Sie async/await verwenden: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

der Operator waitit hält die Ausführung der asynchronen Funktion an, bis das Promise gelöst ist, und gibt den Wert zurück. Auf diese Weise sieht Ihr Code synchroner aus:

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

Abfragen werden nacheinander ausgeführt.

7
vsenko

Heutzutage unterstützt mongoose Versprechen, so dass Sie Ihre Anfragen .then() können. Zum Beispiel:

app.get('/notifications', 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);
  });
});

Jetzt, da Javascript async-await hat, können Sie alternativ das verwenden, wodurch einige Zeilen gespeichert und der Code ein wenig abgeflacht wird:

app.get('/notifications', async (req, res, next) => {
  try {
    const user = await Users.findOne({
      username: req.body.username,
      password: req.body.password,
    });
    if (!user) {
      res.json({success: false, message: "Username or password incorrect."});
      return;
    }

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

Zum Synchronisieren habe ich es6-Versprechen verwendet.

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

und ich habe JSON wie folgt.

[
    {
        "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"
            }
        ]
    }
]
3
Kohei Sugimura

Hier ist was ich heute Abend gemacht habe.

mongoose.createConnection("mongodb://localhost:27017/chemresearch")
.then(async db => {
    const collection = db.collection("chemical");
    const all = collection.find({});

    while(all.hasNext()) {
        let chemical = await all.next();
        await work(chemical);
    }
});

Die work-Methode gibt gerade ein Versprechen zurück.

const work = (chemical) => new Promise((resolve, reject) => {
    const casNumber = chemical.casRegistryNumber;
    analysis(casNumber, (error) => {
        error ? reject(error) : resolve(casNumber);
    })
});
0
Proximo

Hier ist eine alternative Methode zum Erstellen pseudo-synchroner Anforderungen mit MongooseJS. Die Idee hierbei ist, eine Warteschlange mit Abfragen zu erstellen, die ausgeführt werden müssen. Erstellen Sie dann eine Funktion, die rekursiv aufgerufen wird, bis die Warteschlange erschöpft ist. Sobald die Warteschlange erschöpft ist, wird die Rekursion angehalten und eine Antwort für die ursprüngliche Anforderung zurückgesendet. Ich verwende Expressrouten, daher ist der gesamte Code in meinem Routenhandler gekapselt. In diesem Fall ein 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;
0