2

So I have this array of strings which I'm using as filter to fetch documents from MongoDB using Mongoose. I'm successfully getting the data back from the db, but it is also returning Promise { <pending> } on the console even though I'm wrapping the map function with Promise.all.

Please note that this map function is nested inside two level deep for in loops which I'm leaving out for simplicities sake.

Suppose this is the array of strings:

const subCategories = [ 'Politics', 'Entertainment' ];

And this is the map function:

const subCategoryID = await Promise.all( subCategories.map( async item => {
  try {
    const data = await SubCategory.findOne( { subCategory: item } );
    return data;
  } catch( e ) {
    throw err;
  }
}));

console.log( subCategoryID );

Promises make my head spin. I have tried learning Promises more than 5-6 times in the last 1-2 years and it still confuses me. So if you can, please provide a solution with Async/Await.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
s.khan
  • 297
  • 1
  • 7
  • 24
  • 1
    I think your issue is with Mongoose, not Promises. You are not executing your query with `.exec()`? Your question may make heads spin too - Suppose array of strings, yet in your map callback you attempt to use the string as such: `item.label` - strings don't have a label property. So your Mongo document that is in subcategories should sort of be shown to some extent too. – Randy Casburn Oct 30 '21 at 18:07
  • @RandyCasburn Sorry about that. It is actually an object but to avoid complications in the post I turned it to a string. I'll just edit it. – s.khan Oct 30 '21 at 18:08
  • 1
    I realize that, but it gets people curious about what other glaring omissions/mistakes are here. Clarity is always better in your question. But, as I said, I think you forget to execute your query. – Randy Casburn Oct 30 '21 at 18:10
  • No there's nothing else. I have just omitted the for in loops and made the object to string. And the query is being made as I'm getting the data from the db. – s.khan Oct 30 '21 at 18:12
  • 1
    I'm pretty sure I'm correct. Without using `.exec()` as in your code, a _thenable_ is being returned with your data, hence the promise in the console. Please [read this answer in another question to realize my point.](https://stackoverflow.com/a/68469848/9078341) Your issue is with how you are using Mongoose. – Randy Casburn Oct 30 '21 at 18:17
  • you want the result with different quicker approach or you want the explanation of your code? I assume you want to get the filtered documents – Jastria Rahmat Oct 30 '21 at 18:18
  • @RandyCasburn Thanks for that link. Learnt some new things. However, I'm still getting Promise pending after using exec() – s.khan Oct 30 '21 at 18:22
  • @JastriaRahmat Yes I want to get the filtered documents. Any approach is fine but if you can then please tell me why my approach is giving me a promise pending. That'd help me learn a bit. – s.khan Oct 30 '21 at 18:24
  • 1
    @RandyCasburn No problem with not using `.exec()`. The queries are thenable, and using `await` or `Promise.all()` on them will run them and give the expected result. – Bergi Oct 30 '21 at 19:54
  • 1
    @s.khan Are you certain that `console.log( subCategoryID );` does log a promise? That sounds like in your actual code you have forgotten the `await` on `Promise.all(…)` - an `await` expression *never* returns a promise. – Bergi Oct 30 '21 at 19:55
  • 1
    Btw, that `catch ( e ) { throw err; }` is at best superfluous and at worst wrong (referencing the undeclared variable `err` instead of `e`). Just don't wrap the code in that `try` block and it will do absolutely the same. – Bergi Oct 30 '21 at 19:56
  • 1
    @Bergi I figured out the problem. I was not using await to the actual function in which the whole loops, maps, etc are in. Which is what is showing Promise pending. The chosen answer is not the actual solution but it did help me write the query in a simple way. – s.khan Oct 30 '21 at 20:04
  • And thanks a lot @Bergi for the suggestion. I'll just remove that. – s.khan Oct 30 '21 at 20:05

1 Answers1

3

If you're only interested in the result, Try this approach:

const subCategories = [ 'Politics', 'Entertainment' ];

const queries = subCategories.map((i) => {
  return { subCategory: i };
});

const subCategoryID = await SubCategory.find({
  $or: queries,
});

console.log(subCategoryID);

using $or operator is explained in mongodb manual:

The $or operator performs a logical OR operation on an array of two or more <expressions> and selects the documents that satisfy at least one of the <expressions>.

more about it here.

In mongoose, you can use it in any find methods.

for explanation about your promise, sorry I can't help.

Please mark answered if this solves your problem.

Jastria Rahmat
  • 776
  • 1
  • 6
  • 27