0

I am building an App and I have a problem inside a for loop.

Inside my function I got two arrays as arguments (payload.data.start and payload.data.end) and I am trying to push it inside the mongodb. My code looks like this

async function emplaceAval (state, payload, blockInfo, context) {
  for(var i=0 ; i<payload.data.start.length ; i++) // start and end have the same length
  {
    const user =await User.findOne({ 'account': payload.data.account })
    user.availability.push({start: new Date(payload.data.start[i]+'Z') , end: new Date(payload.data.end[i]+'Z')});
    await user.save();
  }
}

The problem is that lots of times I lose data. By losing data I mean that the i changes before user.save take place.

I consider to use forEach , but I have two arrays that need to be save together , so I cant .

The second solution I thought is to create an index array . For example if the length of my arrays is 5 , I will create an indexTable=[0 , 1 , 2 , 3 , 4 ] and I will use asyncForEach to this array. But i dont think that this solution is the preferable. Any ideas? Thanks in advance

11
  • 3
    await & function (err, user) are not compatible with each other,.. IOW: if you want mongoDb to use promise, don't use callbacks. eg. try.. const user = await User.findOne({ 'account': payload.data.account }); Commented Nov 2, 2018 at 19:11
  • 1
    I don't use mongodb, I would expect save to also be async,.. so maybe try await user.save(); Also could you show us your updated code, just update your question. Commented Nov 2, 2018 at 19:16
  • 2
    that the i changes before user.save, looking at your revised code, that shouldn't now be happening,. But I would change var i to let i anyway, this will create a block scoped variable, so I won't be lost even if your async op's go out of sync. Commented Nov 2, 2018 at 19:28
  • 1
    await only works if function returns a promise. Just changing var to let is dummy solution as this will solve problem of closure not promise. Do read more about async-await and promise. Also check what does user.save and other functions called inside for-loop returns. Commented Nov 2, 2018 at 20:30
  • 1
    Why are you looping at all? It seems to me this is just a simple $push operation with $each. Show the data you want to update and the expected change made to the document(s), You're concentrating on Promises where that is no the part of the problem which actually needs resolving. Commented Nov 2, 2018 at 22:04

1 Answer 1

2

From what I can see here the looping is completely unneccesary. MongoDB has a $push operator which allows update of an array without retrieving the document first. This also has an $each option to allow a list of elements to be "pushed" in the singe update.

In short this is just one request and response to the server to await:

// Transpose to array of objects for update
let availability = payload.data.start.map((e,i) =>
  ({ start: new Date(e+'Z'), end: new Date(payload.data.end[i] + 'Z') })
);

try { 
  // Perform the **one** update request
  let response = await User.updateOne(
    { 'account': payload.data.account },
    { '$push': { 'availability': { '$each': availability } } }
  );

  // maybe check the response
} catch(e) {
  // do something with any error
}

That's all you need do. No need to "loop" and so much less overhead than going back and forth to the server retrieving a document and making changes then putting the document back.

Sign up to request clarification or add additional context in comments.

Comments

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.