0

I have a string

var my_str = "Jenny [id:51], david, Pia [id:57], Aston [id:20], Raj, ";

I am sending this to a function convert_to_array(my_str) and want something like this in return

[all: [51, 72, 57, 20, 73], new: [72, 73]]

Here, 72 & 73 are newly inserted documents to a mongodb database.

This is what I am doing:

function convert_to_array(text) {
if(text && text !== '') {

    var text_arr = text.split(', ');
    text_arr.pop();

    var arr = new Array();
    var new_profiles = new Array();
    var all_profiles =  new Array();

    for(var i = 0; i < text_arr.length; i++) {
        var pair = text_arr[i].split('[id:');

        // Its already existing, just add it to the array
        if(pair[1]) {
            all_profiles.push(pair[1].split(']')[0]);

        // Else create a new profile and pass the _id
        } else {

            // Save to db first
            var profileObj = new Profile({name: pair[0], automated: true});
            profileObj.save(function(err, data) {

                if(err) throw err;

                all_profiles.push(String(data._id));
                new_profiles.push(String(data._id));
            });
        }
    }
    arr = {all: all_profiles, new: new_profiles};
    return arr;
}
}

With this code, I am getting only this (or something similar, I cant remember the exact output)

    [all: [51, 57, 20], new: []]

The item is saved in database, I can see that. But as node is non-blocking in nature, the for loop finishes and returns before the data is saved in database & and pushes the id to the aray. I tried with async, but still couldn't figure out how to solve this issue.

I added few console.logs to see how it executes, here it goes:

yes existing: 51
oh! doesnt exist. creating: david
yes existing: 57
yes existing: 20
oh! doesnt exist. creating: Raj
GET /page/delete_later 200 4ms
Ok created now: 72
Ok created now: 73

I am so confused on how to code it node-friendly!

1 Answer 1

1

You need to change your convert_to_array function so that it calls a callback when the result is done, instead of returning the result a return value.

function convert_to_array(text, callback) {
   // do some stuff, call this when done:
   //    callback(null, arr);
   // or this on error:
   //    callback(err);
}

Now when your result is ready? It's when all text_arr items were processed (i.e. all calls to profileObj.save are finished). Probably the simplest way how to express this in code is to use async module (npm install async):

var async = require('async');
// ...

function convert_to_array(text, callback) {
  if(text && text !== '') {

    var text_arr = text.split(', ');
    text_arr.pop();

    var arr = new Array();
    var new_profiles = new Array();
    var all_profiles =  new Array();

    async.eachSeries(text_arr, function(it, done) {
      var pair = text_arr[i].split('[id:');

      // Its already existing, just add it to the array
      if(pair[1]) {
        all_profiles.push(pair[1].split(']')[0]);
        next(); // !important! tell async we are done
      // Else create a new profile and pass the _id
      } else {
        // Save to db first
        var profileObj = new Profile({name: pair[0], automated: true});
        profileObj.save(function(err, data) {
            if(err) {
              // throw err; // use callback instead of throw for error handling
              next(err);
              return;
            }
            all_profiles.push(String(data._id));
            new_profiles.push(String(data._id));
            next(); // !important! tell async we are done
        });
    }, function(err) { 
      arr = {all: all_profiles, new: new_profiles};
      callback(err, arr);
    }

  } else {

    callback(null, undefined); // alter depending on your requirements
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Miroslave! I will try this out asap. Actually I played with the async.eachSeries for this, but couldn't make it return what I wanted. I think its the next() call after finishing .save()! The readme of async is really confusing :p

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.