简体   繁体   中英

node.js async array save data to mongodb

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!

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 (ie 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
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM