¿Alguien puede ayudarme sobre cómo puede ejecutar la consulta mongoose en forEach loop en nodejs y sugerir la necesidad de resultados de unión interna de ambas colecciones?
como debajo de los detalles
userSchema.find({}, function(err, users) { if (err) throw err; users.forEach(function(u,i){ var users = []; jobSchema.find({u_sno:susno}, function(err, j) { if (err) throw err; if (!u) { res.end(JSON.stringify({ status: 'failed:Auction not found.', error_code: '404' })); console.log("User not found."); return } users.push(j); }) }) res.send(JSON.stringify({status:"success",message:"successfully done",data:{jobs:j,users:u}})); })Schema.find() es una función asíncrona. Por lo tanto, su última línea de código se ejecutará mientras espera que se ejecute la primera búsqueda de trabajo en su bucle. Sugiero cambiarlo a Promises y usar Promise.all (array).
Para hacerlo, primero debe cambiar para usar Promise con mangosta. puedes hacer esto con bluebird así:
var mongoose = require('mongoose'); mongoose.Promise = require('bluebird');Entonces puede usar Promesas en lugar de devoluciones de llamada como esta:
userSchema.find({}).then(function(users) { var jobQueries = []; users.forEach(function(u) { jobQueries.push(jobSchema.find({u_sno:susno})); }); return Promise.all(jobQueries ); }).then(function(listOfJobs) { res.send(listOfJobs); }).catch(function(error) { res.status(500).send('one of the queries failed', error); });EDITAR Cómo enumerar trabajos y usuarios
Si quieres tener una estructura como:
[{ user: { /* user object */, jobs: [ /* jobs */ ] }]podría fusionar las listas. listOfJobs está en el mismo orden que la lista jobQueries, por lo que están en el mismo orden que los usuarios. Guarde a los usuarios en un ámbito compartido para obtener acceso a la lista en la 'función luego' y luego fusione.
.. }).then(function(listOfJobs) { var results = []; for (var i = 0; i < listOfJobs.length; i++) { results.push({ user: users[i], jobs: listOfJobs[i] }); } res.send(results); }).catch(function(error) { res.status(500).send('one of the queries failed', error); });Una solución agradable y elegante es usar la función cursor.eachAsync() . Crédito a https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js .
La función eachAsync() ejecuta una función (potencialmente asíncrona) para cada documento que devuelve el cursor. Si esa función devuelve una promesa, esperará a que se resuelva esa promesa antes de obtener el siguiente documento. Esta es la forma más fácil de agotar un cursor en mongoose.
// A cursor has a `.next()` function that returns a promise. The promise // will resolve to the next doc if there is one, or null if they are no // more results. const cursor = MyModel.find().sort({name: 1 }).cursor(); let count = 0; console.log(new Date()); await cursor.eachAsync(async function(doc) { // Wait 1 second before printing first doc, and 0.5 before printing 2nd await new Promise(resolve => setTimeout(() => resolve(), 1000 - 500 * (count++))); console.log(new Date(), doc); });No es necesario usar forEach() que es síncrono y se llama de forma asíncrona, lo que le dará resultados incorrectos.
Puede usar el marco de agregación y usar $lookup , que realiza una unión externa izquierda a otra colección en la misma base de datos para filtrar documentos de la colección "unida" para su procesamiento.
Por lo tanto, la misma consulta se puede realizar mediante una canalización de agregación única como:
userSchema.aggregate([ { "$lookup": { "from": "jobs", /* underlying collection for jobSchema */ "localField": "sno", "foreignField": "u_sno", "as": "jobs" } } ]).exec(function(err, docs){ if (err) throw err; res.send( JSON.stringify({ status: "success", message: "successfully done", data: docs }) ); })