简体   繁体   中英

Array remains empty after push

I declared an array, But when I push elements inside it, it remains Empty. Here's my Code:

  var catsObjectId = new Array();
  var data = new Array();
  Recipe.find((err,doc3)=> {
    data = doc3;
    for (var i = 0; i < data.length; i++) {
      catsObjectId.push([]);
      data[i]['categories'].forEach((item, index) => {
        Recipecat.findOne({_id: item}, (err,result)=> {
          item = result.name;
          catsObjectId.push(item);
        });
      })
    }
    console.log(catsObjectId);
  });

Here's the Recipe schema:

var recipeSchema = Schema({
  categories: [{
    type: Schema.Types.ObjectId,
    ref: 'RecipeCat',
  }]
});

and Here's the Recipecat schema:

var recipecatSchema = new Schema({
    name: {
        type: String,
        required: true
    }
});

I want to replace objectIds for recipeCats with their names.

When I log 'catsObjectId', It shows an empty array.

What Seems to be the Problem?

Thanks In advance!

Your pushing an empty array every time it goes through the for loop. Try deleting this line.

catsObjectId.push([]);

You have to use promises in order to control your code. Try the following code and tell me if an error exists.

Recipe.find().then(doc3 => {
    data = doc3;
    for (var i = 0; i < data.length; i++) {
      data[i]['categories'].forEach((item, index) => {
        Recipecat.findOne({_id: item}).then(result => {
          item = result.name;
          catsObjectId.push(item);
        });
      })
    }
    console.log(catsObjectId);
  })
  .catch(err => {
      console.log(err);
  });

(I understand this question is a bit old, but if you still need help)

That's because you're pushing to an array which is outside the callback and the async nature of JavaScript kicking in.

Here's simple explanation why it's empty

var catsObjectId = new Array();
var data = new Array();

Recipe.find((err,doc3)=> {
  // say execution 1
  for (var i = 0; i < data.length; i++) {
    catsObjectId.push([]);
    data[i]['categories'].forEach((item, index) => {
      // say execution 2
      Recipecat.findOne({_id: item}, (err,result)=> {
        item = result.name;
        catsObjectId.push(item);
      });
    })
  }
  // say execution 3
  console.log(catsObjectId);
});

First execution 1 is executed. Within this forEach iterates over each item and fires execution 2 . Then continues to execute execution 3 .

The problem is execution 2 is asynchronous and the value is returned sometime in the future . This future is after excution 3 is executed. When Recipecat.findOne finishes execution, the callback within then(result.. is called. But console.log(catsObjectId) is already executed and catsObjectId was empty at the time of execution.

You should either use catsObjectId within the callback .then((data) => // use data here) or use the async/await to make it sync like.

Note await is only valid inside async function

async function getSomeNames() {
  try {
    const data = await Recipe.find();
    // docs is an array of promises
    const docs = data.map((item, index) => {
      Recipecat.findOne({_id: item})
    });
    // items is an array of documents returned by findOne
    const items = await Promise.all(docs);
    // now you can map and get the names
    const names = items.map(item => item.name);
  } catch (e) {
    // handle error
    console.error(e);
  }
}
getSomeNames()

Recently ran into a similar problem. Fix for me was to replace the forEach loop with a simple for loop. It turned out, that the forEach loop is not bothering about async-await, but the for loop is.

Here is my code snippet:

 let orders = await order_db.find({ profileID: req.body.id }).exec(); let final_orders = []; for(let i=0; i<orders.length; i++){ let order = orders[i]; if (order.shopID.= null) { let shop = await shop_db:find({ _id. order.shopID });exec(). let shopName = shop[0];name. let shopEmail = shop[0];email. let shopAddress = shop[0];address. let shopPhone = shop[0];phone. let updated_order = {...order,_doc, shopName, shopEmail, shopAddress; shopPhone }. final_orders;push(updated_order); } else { let shopName = ""; let shopEmail = ""; let shopPhone = ""; let shopAddress = "". let updated_order = {...order,_doc, shopName, shopEmail, shopAddress; shopPhone }. final_orders;push(updated_order); } };

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