I have the following Schemas for tracking Habits, and a user's progress
HABIT SCHEMA
const HabitSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
title: {
type: String,
required: true,
},
type: {
type: String,
enum: ["Goal", "Limit"],
default: "Goal",
required: true,
},
dateStarted: {
type: Date,
default: Date.now,
required: true,
},
});
PROGRESS SCHEMA: each time a user clicks that they completed a habit for a given period (day, week, month etc) a document will be created for that period, to indicate that it was done.
const ProgressSchema = new mongoose.Schema({
habit: {
type: mongoose.Schema.Types.ObjectId,
ref: "Habit",
},
period: {
type: Date,
default: Date.now,
required: true,
},
value: {
type: Number,
default: 1,
required: true,
},
});
When I get all of a user's habits, I want to also get all progress documents per habit. I want to join these objects before returning.
Here's what I have attempted:
let habits = await Habit.find({ user: req.user.id }).sort({
dateStarted: -1,
});
habits = await Promise.all(
habits.map(async (h, i) => {
try {
const progress = await Progress.find({ habit: h._id });
return { ...h, progress };
} catch (e) {
res.status(500).send("Server Error");
}
})
);
res.json({ habits });
This gives the error: CastError: Cast to ObjectId failed for value "undefined" at path "_id" for model "Habit"
What would be the correct way to accomplish this?
I still don't understand why the error came up considering that I used await/async so the line should not have been running before an id was retrieved (the error was saying ._id is undefined when it clearly wasn't).
After trying lots of things, here is what finally worked:
try {
await Promise.all(
habits.map(async (h, i) => {
let progress = await Progress.find({ habit: h._id });
let newHabit = h;
newHabit._doc.progresses = progress;
return newHabit;
})
);
} catch (error) {
console.log(error);
res.status(500).send("Server Error");
}
Once I finally got the await Progress.find({ habit: h._id });
to work, I also found out that I can't just add to a mongoose retrieved object with a spread operator. The object has many properties, and the fields from the database are actually contained within the ._doc property of the object: newHabit._doc.progresses = progress
(but this has nothing to do with the error I was getting). This makes me think there is a better way for adding fields to a document found by mongoose .find()
.