2

I have multiple collections in which every record has a "tags" field. For example:

Collection A:
{name: "1", tags: "foo, bar"}
{name: "2", tags: "foo"}
Collection B:
{name: "3", date: "today", tags: "bar"}

And now I want to use the tags of one record to search all collections for matching results. For example, when I do a search on A (tags: "foo, bar"), ideally I'll get all three records. So I split the tags and do the search like this:

let a = {name: "1", tags: "foo, bar"};
var finalResult = [];
let tags = a.tags.split(', '); // Get separated tags

for (i=0;i<tags.length;i++) { // Iterate through every tag

  // Find matching results in Collection A
  CollectionA.find({tags: {$regex : ".*" + tags[i] + ".*"}}, (err, AResults) => {
    for (step=0;step<archives.length;step++) {
      finalResult.push(AResults[step]);
    };

    // Find matching results in Collection B after A is done
    CollectionB.find({tags: {$regex : ".*" + tags[i] + ".*"}}, (err, BResults) => {
      for (step=0;step<archives.length;step++) {
        finalResult.push(BResults[step]);
      };

      res.send(finalResult);

    };

  };

}

Actually the search goes right and got me the result, but it sends twice because of the loop. Also the app crashes with error:

Error: Can't set headers after they are sent.

So I wanted to solve the problem by only add a condition of "i = tags.length" before res.send, but it doesn't work, and when I console log "i", it just gives me two lines of "2", which is odd because it should have reached that until after the iteration is done. I think it has something to do with the asynchronous-ness of MongoDB commands but have absolutely no idea how to solve the problem. Any suggestions? Many thanks in advance.

Bárbara Peres
  • 585
  • 1
  • 9
  • 26
Agustín Dorado
  • 294
  • 2
  • 11
  • At least closely related: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example But perhaps there's a MongoDB-specific aspect? – T.J. Crowder Oct 19 '18 at 12:08
  • 1
    @T.J.Crowder A thousand thanks! I just changed it "let i = 0" in the iteration syntax and now it magically works. – Agustín Dorado Oct 19 '18 at 13:42
  • 1
    So can we not write answers for this any more? This isn't the usual way of combining asynchronous tasks. I would have said that you can do it using `Promise.all`, or something in the `async` library. Also, in this case you don't even need to loop over `tags`, because it's done with a regex and you can use the `|` regex character. Just do: `CollectionA.find({tags: {$regex : ".*(" + tags.join('|') + ").*"}}, ...);`. – David Knipe Oct 19 '18 at 14:22
  • @DavidKnipe thx! Gonna look into that – Agustín Dorado Oct 20 '18 at 02:07

0 Answers0