'Node.js/MongoDB - Returned document seems to revert back to a promise, even after I've awaited it
I'm doing what feels like a simple query, and this is a two part question. The first is whether there's a better way to do it, given my data structure, and the second is, if not, why am I seeing this behavior in my current implementation?
I am building a quizzing app - Node.js backend with MongoDB. I have a "questions" collection - here's a sample document from that:
{
"_id": ObjectId("62742bb0dbf1a0577864bbeb"),
"category": "World History",
"results": [],
"text": "**What volcano** erupted in 79AD, burying the cities of Pompeii and Herculaneum?",
"answer": "Mt. Vesuvius",
"owner": ObjectId("605271517fce7249cc8eb436"),
"__v": 0
}
I have a "quizzes" collection, where documents can have an array of questions from the questions collection:
{
"_id":ObjectId("62800d4d1d7c821198121193"),
"type": "std",
"questions": [{
"id": ObjectId("627034e92dda695b884a632e"),
"value": 2
},
{
"id": ObjectId("627160ec79517a79180f1e41"),
"value": 2
},
{
"id": ObjectId("62742bb0dbf1a0577864bbeb"),
"value": 4,
}
],
"title": "test standard quiz",
"description": "this is a test standard quiz\n\nthis is a second line.",
"owner": ObjectId("605271517fce7249cc8eb436"),
"__v": 0
}
At least in theory, this should allow users to create questions, and add them to as many quizzes as they want with different point values, if they wish. Doing an aggregation led to some trouble, as the ObjectIDs for the questions is embedded in an object, since they need to have a point value tied to them as well. Here's my kludgy way of joining the two collections:
const getQuizDetails = async ()=> {
const Quiz = require('./models/quizModel');
const Question = require('./models/questionsModel');
const owner = '605271517fce7249cc8eb436'; //just for testing, I'm hard-coding the owner's ID here
const results = await Quiz.find({
owner,
type: 'std',
});
console.log(results); //This gives an array with the document(s) as expected.
const vals = results.map(r=> {
return r.questions.map(q=> {
return q.value;
}
}
console.log(vals); //This gives an array of arrays, containing the values of each question in each of the results above (e.g. [[2,2,4]] if we just returned the sample document above)
let qs;
for (var i = 0; i < results.length; i++) {
qs = await Promise.all(
results[i].questions.map((q) => {
return Question.findById(q.id);
})
);
q2 = qs.map((q, j) => {
return {
...q,
value: vals[i][j],
};
});
console.log(qs); //This gives an array of questions, with the text and answer of each one, which is what I want.
console.log(q2); //This gives something unexpected.
}
}
Above, when I log the variable qs, I get an array with the question details, with the question text, category, and answer:
{
category: 'Pop Music',
results: [],
_id: 627160ec79517a79180f1e41,
text: `Dua Lipa's 2021 hit "Cold Heart" features **what other artist**? His song "Sacrifice" provides both the title and many of the lyrics of "Cold Heart".`,
answer: 'Elton John',
owner: 605271517fce7249cc8eb436,
__v: 0
},
{
category: 'World History',
results: [],
_id: 62742bb0dbf1a0577864bbeb,
text: '**What volcano** erupted in 79AD, burying the cities of Pompeii and Herculaneum?',
answer: 'Mt. Vesuvius',
owner: 605271517fce7249cc8eb436,
__v: 0
},
{
category: 'Art',
results: [],
_id: 627435e1bd9f6b4bcc057761,
text: 'Who painted the Mona Lisa?',
answer: 'Leonardo da Vinci',
owner: 605271517fce7249cc8eb436,
__v: 0
},
I would expect, since I have an array of objects (and not promises anymore...are they?), that mapping it with another array (of numbers) would be straightforward. However, this is not the case. When I log q2, I get an array of objects similar to this:
{
'$__': InternalCache {
strictMode: true,
selected: {},
shardval: undefined,
saveError: undefined,
validationError: undefined,
adhocPaths: undefined,
removing: undefined,
inserting: undefined,
saving: undefined,
version: undefined,
getters: {},
_id: 627ad0c89041f24a60469288,
populate: undefined,
populated: undefined,
wasPopulated: false,
scope: undefined,
activePaths: [StateMachine],
pathsToScopes: {},
cachedRequired: {},
session: undefined,
'$setCalled': Set(0) {},
ownerDocument: undefined,
fullPath: undefined,
emitter: [EventEmitter],
'$options': [Object]
},
isNew: false,
errors: undefined,
'$locals': {},
'$op': null,
_doc: {
category: 'Geography',
results: [],
_id: 627ad0c89041f24a60469288,
text: 'What is the capital of Georgia?',
answer: 'Tblisi',
owner: 605271517fce7249cc8eb436,
__v: 0
},
'$init': true,
value: 10
}
All of the information that I need is there (the question information plus the point value), but I have a lot of other stuff as well - if I were to guess, it's the structure of a promise or something, but there shouldn't be any unresolved promises here - I've awaited them all, and they logged to the console as resolved objects. What's going on here?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
