Code inside .then executing before the Promise Code inside .then executing before the Promise mongoose mongoose

Code inside .then executing before the Promise


I haven't used the Spotify APIs before, so I can't say much about that but there are a couple of issues I see at first glance. First, you're checking if (array !== 'undefined') {, which is checking if the array variable is a string that is literally 'undefined' (not the value undefined). I'm fairly certain that is not what you intended. You would be better off using Array.isArray(array) here, if you're wanting to make sure array is actually an Array.

Second, you're using async functions and Promises mixed together, which (imo), you generally shouldn't do. You should use one or the other, so it's consistent and easier to follow. If you use await instead of .then, you will be able to write it in a more "synchronous" fashion and it should be easier to understand.

import * as data from '../spotify_data/artist_id.json';async function fillGenres(array) {  const genreIDs = []; // array of genre object IDs I'm trying to put inside every appropriate artist  if (Array.isArray(array)) {    for (const element of array) {      const result = await Genre.findOrCreate({ name: element });      genreIDs.push(result._id);    }  }  return genreIDs;}async function fillRest(entry, genreIDs) {  const artist = {    name: entry.ArtistName,    genres: genreIDs,    spotifyID: entry.ArtistID,    popularity: entry.Popularity,    spotifyFollowers: entry.Followers,  };  try {    const result = await Artist.create([artist]);    console.log(result);  } catch (error) {    console.log(error);  }}async function spotifySeed() {  const entries = Object.values(data);  for (const entry of entries) {     const genreIDs = await fillGenres(entry.Genres);     await fillRest(entry, genreIDs);  }}await spotifySeed();


I don't know anything about the Spotify API, so this is just a guess. In fillGenres, you have:

await Genre.findOrCreate({ name: element }, (err, result) => {  genreIDs.push(result._id);});

You're passing a callback function. Sometimes libraries will allow you to use promises or callbacks. If you pass a callback, it won't return a promise. So I'm guessing that the loop starts off all the calls to Genre.findOrCreate, which doesn't return a promise since you're using a callback. and then immediately returns. Then fillRest is called and may finish before all the Genre.findOrCreate calls.

You want something like:

const result = await Genre.findOrCreate({ name: element });genreIDs.push(result._id)

Though even better would be this:

function fillGenres(genreNames) {  if(!genreNames || !genreNames.length) return Promise.resolve([])  return Promise.all(genreNames.map(name => {    return Genre.findOrCreate({ name })      .then(result => result._id)  })}

This will run all the genre calls at the same time and return them all when they're done, rather than waiting to add one after another (as in your for loop).

If Genre.findOrCreate does not return a Promise, you could create a version that does:

function genreFindOrCreate(data) {  return new Promise((resolve, reject) => {    Genre.findOrCreate(data, (err, result) => {      if(err) reject(err)      else resolve(result)    })  })}