Home > Mobile >  nodejs filtering an array of objects where the filtering is partially done in an async function
nodejs filtering an array of objects where the filtering is partially done in an async function

Time:02-11

I've read many similar questions and have tried a bunch of code. Unfortunately, I'm not getting my code to run :-(

So, the situation is as follows: In a route of a node.js server, I have to respond with a filtered array of Objects. Unfortunately, whatever I do, I always get an empty array [] back. The filter is a bit tricky in my opinion, as it consists of a string comparison AND an async call to a library function. With the console output, I can clearly see that the correct element is found, but at the same time I see that I've already received the object...

Here is some code that exemplifies my challenge:

let testArray = [
  {
    id: 'stringId1',
    data: {
      someDoc: {
        moreContent: 'Some random content',
        type: 'noInterest'
      }
    }
  },
  {
    id: 'stringId2',
    data: {
      someDoc: {
        moreContent: 'Some random content',
        type: 'ofInterest'
      }
    }
  },
  {
    id: 'stringId3',
    data: {
      someDoc: {
        moreContent: 'Some random content',
        type: 'ofInterest'
      }
    }
  }
]

// code from a library. Can't take an influence in it.
async function booleanWhenGood(id) {
  if (id in some Object) {
    return { myBoolean: true };
  } else {
    return { myBoolean: false };
  }
}

// Should return only elements with type 'ofInterest' and that the function booleanWhenGood is true
router.get('/', function(res,req) {
  tryOne(testArray).then(tryOneResult =>{
    console.log('tryOneResult', tryOneResult);
  });
  tryTwo(testArray).then(tryTwoResult => {
    console.log("tryTwoResult ", tryTwoResult);
  });

  result = [];
  for (const [idx, item] of testArray.entries() ) {
    console.log(idx);
    if (item.data.someDoc.type === "ofInterest") {
      smt.find(item.id).then(element => {
        if(element.found) {
          result.push(item.id);
          console.log("ID is true: ", item.id);
        }
      });
    }

    if (idx === testArray.length-1) {
      // Always returns []
      console.log(result);
      res.send(result);
    }
  }
})


// A helper function I wrote that I use in the things I've tried
async function myComputeBoolean(inputId, inputBoolean) {
  let result = await booleanWhenGood(inputId)
  
  if (result.myBoolean) {
    console.log("ID is true: ", inputId);
  }

  return (result.myBoolean && inputBoolean);
}

// A few things I've tried so far:
async function tryOne(myArray) {
  let myTmpArray = []

  Promise.all(myArray.filter(item => {
    console.log("item ", item.id);
    myComputeBoolean(item.id, item.data.someDoc.type === "ofInterest")
    .then(myBResult => {
      console.log("boolean result", myBResult)
      if (myBResult) {
        tmpjsdlf.push(item.id);
        return true;
      }
    })
  })).then(returnOfPromise => {
    // Always returns [];
    console.log("returnOfPromise", myTmpArray);
  });

  // Always returns []
  return(myTmpArray);
}

async function tryTwo(myArray) {
  let myTmpArray = [];
  myArray.forEach(item => {
    console.log("item ", item.id);
    myCompuBoolean(item.id, item.data.someDoc.type === "ofInterest")
    .then(myBResult => {
      console.log("boolean result", myBResult)
      if (myBResult) {
        myTmpArray.push(item.did);
      }
    })
  });

  Promise.all(myTmpArray).then(promiseResult => {
    return myTmpArray;
  });
}

Asynchronous programming is really tough for me in this situation... Can you help me get it running?

CodePudding user response:

I didn't inspect your attempts that closely, but I believe you are experiencing some race conditions (you print return and print the array before the promises resolve).

However you can alwayd use a regular for loop to filter iterables. Like this:

let testArray = [
    {
        id: 'stringId1',
        data: {
            someDoc: {
                moreContent: 'Some random content',
                type: 'noInterest'
            }
        }
    },
    {
        id: 'stringId2',
        data: {
            someDoc: {
                moreContent: 'Some random content',
                type: 'ofInterest'
            }
        }
    },
    {
        id: 'stringId3',
        data: {
            someDoc: {
                moreContent: 'Some random content',
                type: 'ofInterest'
            }
        }
    }
]

async function booleanWhenGood(id) {
    if (id in { 'stringId1': 1, 'stringId2': 1 }) { // mock object
        return { myBoolean: true };
    } else {
        return { myBoolean: false };
    }
}

async function main() {
    let filtered = []
    for (item of testArray)
        if ((await booleanWhenGood(item.id)).myBoolean && item.data.someDoc.type === 'ofInterest')
            filtered.push(item)
    console.log('filtered :>> ', filtered);
}

main()
  • Related