Home > Software design >  Iterating Over an Array of Subdocuments in Express.js
Iterating Over an Array of Subdocuments in Express.js

Time:07-10

I am using MongoDB, Mongoose, Node.js and Express.js on a site. I have researched Tutorials Point, the MongoDB docs, Stack Overflow, and Mongoosejs.com, but can't find the answer to this question. I have this as one of my document models:

const mongoose = require('mongoose')
const Schema = mongoose.Schema;

const QuestionSchema = new Schema ({
    userid: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        required: false
    },
    title: String,
    keyword1: String,
    keyword2: String,
    keyword3: String,
    body: String,
    upvotes: {
        type: Number,
        default: 0
    },
    datePosted: {
        type: Date,
        default: new Date()
    },
    answers: [{
        respondentID: mongoose.Schema.Types.ObjectId,
        respondent: String,
        text: String,
        date: Date,
        upvotes: Number
    }]
});

const Question = mongoose.model('Question', QuestionSchema);

module.exports = Question

On one of the pages, I want to display all of the "answers" which is an array of subdocuments embedded within the "Questions" model you see above. Here is my express.js controller that seeks to "extract" the answers array (the console.log entries are me attempting different approaches to get the answers array):

const { typeOf } = require('mathjs');
const Question = require('../models/Question')

module.exports = async (req,res) =>{
    console.log("You are inside displayAnswers controller!")
    const thisQuestionID = req.body.questionID;
    console.log("Display answers ID: "   thisQuestionID);
    
    if (thisQuestionID == 0) {
        console.log("Inside thisQuestionID == 0")
        res.redirect("index");
    } else {    
        const answers = await Question.find({"_id" : thisQuestionID}, {"answers": 2});   
        console.log("Answers: "   answers)
        console.log("Answer[0]: "   answers.answers[0])
        console.log(typeOf(answers.answers[0]))
        console.log("Answers Length: "   answers[0].length)
        console.log("Answers Size: "   answers[0].size)
        res.render('displayAnswers', {
            thisQuestionID,
            answers
        })
    }
}

The problem I have is that the answers variable shows up like this in the console: enter image description here

But I cannot seem to access the subdocuments. I thought I could say answers[0] or answers[#], where # is 1, or 2 or whatever the index of the subdoc is, etc but anything other than answers[0] is undefined and answers.length always shows up as "1". I can't seem to find the syntax that allows me to iterate over each individual document within the array of subdocuments. I also checked console.log(typeOf(answers)) and it confirmed that it is an array, so I am lost as to why I can't access each subdoc in the array by saying answers[0] and answers1, etc. It is as if Mongoose/Javascript thinks that answers is an array of length 1 and that there is only one element inside of it even though there are two subdocs in there separated by commas.

Any thoughts?

CodePudding user response:

I think you're just getting confused what is the return type, possibly because of bad naming:

const answers = await Question.find({{"_id" : thisQuestionID})

This syntax returns an array of "Questions", just because you project only specific sub fields ("answers" in this case) does not change that.

This means answers looks like this:

[
  { answers: Answer[] }
]

You should either do: ( instead of find we use findOne to simply the code )

const questionBody = await Question.findOne({"_id" : thisQuestionID}, {"answers": 2});
const answers = questionBody.answers

Or even cleaner is to just use distinct

const answers = await Question.distinct("answers", {"_id" : thisQuestionID});

Both will give you an array of answers as you expect.

  • Related