1
votes

Ne pas obtenir de réponse si trouvé à l'intérieur de la boucle node.js mongodb

J'utilise la requête mongodb find dans la boucle car je dois exécuter la requête find 5 fois. Et j'ai utilisé le code ci-dessous pour cela:

let result = {};
let miles = ['5','10','15','25'];

let i = 0;
while (i < miles.length) {
  Shops.find({ 'shopInfo.address':{ $geoWithin:{ $centerSphere: [ [ 75.83183541365247, 30.902146005639267 ], miles[i] / 3959 ] } } }).then(response=>{
      if(i==4){
        result[miles[i]] = response.length;            
        res.json(result);
      }else{
        result[miles[i]] = response.length;            
        i++;
      }
  })
  .catch(err=>{
    console.log(err)
  }); 
}

Et quand j'ai frappé l'api sur le navigateur. Il ne revient avec rien et obtient l'erreur ci-dessous dans la console:

error image

Aidez-moi, comment puis-je résoudre le problème? p >


2 commentaires

Fonctionne-t-il sans la boucle while?


oui, si je l'utilise hors boucle pour obtenir un seul résultat, cela fonctionne bien.


4 Réponses :


0
votes

Les boucles normales ont des problèmes de bouclage sur du code asynchrone. Vous pouvez implémenter une fonction d'assistance asyncForEach:

await asyncForEach(miles, async mile => {
   const response = await Shops.find({ 'shopInfo.address':{ $geoWithin:{ $centerSphere: [ [ 75.83183541365247, 30.902146005639267 ], miles[i] / 3959 ] } } })
   // do soming with the response 
})

Et l'appeler en exécutant vos mongoQueries:

async function asyncForEach(array, callback) {
  if (array)
    for (let index = 0; index < array.length; index++) {
      await callback(array[index], index, array);
    }
}


4 commentaires

Dois-je avoir besoin d'appliquer au-dessus des deux fonctions?


le premier bloc de code déclare la fonction d'assistance asyncForEach et le deuxième bloc de code montre comment utiliser la fonction d'assistance


J'utilise cette fonction d'aide plusieurs fois dans mon projet et je l'ai refactorisée en une classe de fonctions util


for (const mile of miles) {await Shops.find (...)} pourquoi avez-vous besoin d'une aide pour cela?



0
votes

Utilisez async / await pour attendre que la promesse mongo soit résolue, puis incrémentez la variable. Essayez ceci:

async function test() {
  let result = {};
  let miles = ["5", "10", "15", "25"];

  let i = 0;
  while (i < miles.length) {
    try {
      let response = await Shops.find({
        "shopInfo.address": {
          $geoWithin: {
            $centerSphere: [
              [75.83183541365247, 30.902146005639267],
              miles[i] / 3959
            ]
          }
        }
      });
      if (i == 4) {
        result[miles[i]] = response.length;
        res.json(result);
      } else {
        result[miles[i]] = response.length;
        i++;
      }
    } catch (err) {
      console.log(err);
    }
  }
}


1 commentaires

Merci pour votre réponse. Mais non plus ça me donne une erreur pas ça me donne une réponse



2
votes

Ce qui suit se produit:

Votre boucle while s'exécute et démarre une action asynchrone. Cependant comme cette action asynchrone n'est pas encore terminée, le i ++ ne sera pas exécuté, donc la boucle s'exécute indéfiniment, crée de plus en plus d'actions asynchrones qui remplissent votre mémoire, et finalement NodeJS plante car il s'épuise de mémoire. Pour éviter cela, vous ne devez pas itérer de manière synchrone avec une tâche asynchrone. Soit attendez la tâche asynchrone dans une boucle, soit .map les miles des tâches asynchrones puis attendez-les toutes:

 const entries = Promise.all(miles.map(mile =>        
    Shops.find({ 'shopInfo.address':{ $geoWithin:{ $centerSphere: [ [ 75.83183541365247, 30.902146005639267 ], mile / 3959 ] } } })
      .then(entry => ([mile, entry.length]))
 ));

 entries.then(entries => {
   const result = Object.fromEntries(entries);
   //...
});

 // Polyfill: Object.fromEntries
 if(!Object.fromEntries)
  Object.defineProperty(Object, "fromEntries", {
    value(entries) {
      const result = {};
      for(const [k, v] of entries)
        result[k] = v;
       return result;
     }
  });


5 commentaires

@rajat non, Shops.find est asynchrone.


Non, pas vraiment. Le fait qu'une boucle soit synchrone ou non dépend de la façon dont vous l'utilisez.


@rajat oh et au fait, mongodb a une méthode .count () (je ne sais pas comment cela est nommé en mangouste (?)) qui accélérera considérablement votre code.


Avez-vous Node 12.0.0?


J'ai ajouté un polyfill.



0
votes

Voici le code qui a fonctionné pour moi:

let miles = ['5','10','15','25','50'];
async.map(miles,getDistance , function(err, results) {
   if(err){
        console.log(err);
   } 
   res.json(results);
});

function getDistance(mile, callback) {
  Shops.count({ 'shopInfo.address':{ $geoWithin:{ $centerSphere: [ [ 75.83183541365247, 30.902146005639267 ], mile / 3959 ] } } }).then(response=>{
    if(response){
      callback(null,response);
    }
  })
}

J'espère que cela fonctionnera aussi pour vous.


0 commentaires