Multiple async queries in nodejs (mongoose)

Issue

I am a nodejs newbie. I have two simple models, User and Story. Here is what I want to do:

  • I want to retrieve all stories that have {status:"public"} and store it in an array called retrievedStories.
  • Then for each story I want to use its "user" field (which contains the object id of the user) to lookup the name of the user from User
  • Then add a new key in each element of retrievedStories called authorName with the name of the user.

Here are the models:

const UserSchema = new mongoose.Schema({
    googleId: {
        type: String,
        required: true
    },
    displayName: {
        type: String,
        required: true
    },
    firstName: {
        type: String,
        required: true
    },
    lastName: {
        type: String,
        required: true
    },
    image: {
        type: String,
    },
    createdAt: {
        type:Date,
        default: Date.now()
    }
})

const StorySchema = new mongoose.Schema({
    title: {
        type: String,
        required: true,
        trim: true
    },
    body: {
        type: String,
        required: true
    },
    status: {
        type: String,
        default: 'public',
        enum: ['public', 'private']
    },
    user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    createdAt: {
        type:Date,
        default: Date.now()
    }
})

And here is what I tried, but doesn’t work. The stories are retrieved but the authorName is not added. Any help (possibly a better way to do this?) will be highly appreciated!

router.get('/',async (req,res)=>{
    try {
        const retrievedStories = await Story.find(
            {status: "public"}
            )
        await Promise.all(retrievedStories.map(async (story) =>{
            const author = await User.findById(story.user)
            story.authorName = author.displayName
        }))

        return res.json(retrievedStories)
        
    } catch (error) {
        console.log(error)
    }

})

Solution

You can simplify your query by using populate to retrieve User‘s data:

router.get('/', async (req, res) => {
    try {
      const retrievedStories = await Story.find({ status: 'public' })
        .populate('user')
        .exec();
      return res.json(retrievedStories);
    } catch (error) {
      console.log(error);
    }
  });  

You can then access User‘s displayName data on each Story┬áby accessing story.user.displayName.
For more information on query population see the official docs.

Answered By – lpizzinidev

Answer Checked By – David Marino (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.