Banged my head against the wall for past 3-4 hours and checked countless articles here on StackOverflow but could not get my response to populate an array correctly. Using Express.js with Typescript, MongoDB and mongoose. Issue is when I get a response with all the orders my orderedlines array is empty even though I can check and see the ids are there in MongoDB atlas. Here is the actual response:
[
{
"orderedlines": [],
"_id": "6251c61f7385c349f88fe95a",
"userId": {
"favourites": [
"623b39e684b9baf1109053f8",
"623b3afada0e7828602c78df",
"623b3b49da0e7828602c78e7",
"623b39ba84b9baf1109053f7",
"623b3b59da0e7828602c78e9"
],
"_id": "62326179b9c85d3fc833d686",
"orders": [],
"email": "[email protected]",
"username": "stef1222",
"password": "$2b$10$3e5Y/IoyrcJHH3ud6Mn/I.8PfBm2JrEKHwYRd8cQwUaAdz.YkKSMa",
"firstName": "Stefan",
"lastName": "Georgiev",
"image": "https://res.cloudinary.com/dtggdx3hc/image/upload/v1648046254/deqr4chfysogoppafdug.png",
"isAdmin": false,
"hasWriteAccess": false,
"__v": 0
},
"totalPrice": 121.99,
"__v": 0
}
]
As seen above my userId is being populated successfully with all its properties but orderedlines is failing to populate and it is returned as empty array. If I remove the .populate() it returns an array of objects with ids
My findOrdersForUserId function in orderServices where I assume the problem occurs
const findOrdersForUserId = async (
userId: string
): Promise<OrderDocument[]> => {
const ordersToReturn = await Order.find({ userId: userId })
.sort({ _id: 1 })
.populate('userId')
.populate({path:'orderedlines', model:OrderLine})
return ordersToReturn
}
Here is my Order model:
import mongoose, { Document } from 'mongoose'
export type OrderLine = {
orderlineId: string
}
export type OrderDocument = Document & {
userId: string
orderedlines: OrderLine[]
totalPrice: number
}
const orderSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
totalPrice: Number,
orderedlines: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'OrderLine',
},
],
})
export default mongoose.model<OrderDocument>('Order', orderSchema, 'orders')
My OrderLine model:
import mongoose, { Document } from 'mongoose'
export type OrderLineDocument = Document & {
productId: string
userId: string
quantity: number
price: number
}
const orderLineSchema = new mongoose.Schema({
quantity: { type: Number, default: 1 },
price: Number,
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Product',
required: true,
},
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
},
})
export default mongoose.model<OrderLineDocument>('OrderLine', orderLineSchema, 'orderlines')
Mongoose version used: [email protected]
Node version: v16.13.0
Mongo Shell version: v5.0.6
Express version: [email protected]
I would list some of the articles I tried to fix my the issue without success:
- Mongoose populate returning empty array
- Mongoose populate() returning empty array
- Mongoose populate() returns empty array with no errors
- Mongoose Populate not working with Array of ObjectIds
- Populate method not populating my comment array
- Mongoose populate does not populate array
- Mongoose populate not populating an array and always returns an empty array
Edit: All the code is a part of a fork from a repo that is set to private. I am not sure how can I share access/link to the fork for a better preview of the code. Please enlighten me if you would like to see something else or a more specific part of the code.
2
Answers
Answering my own question because I struggled with this a lot and want to help future people reading this question. First of all and really important issue might be if you are not specificying a collection name. In order to specify a collection name add a third argument in your model creation like so:
Before the third argument mongoose was creating a collection name with a lower-cased plurarized model name - orderlines. But when I was trying to populate my response I was referring to orderLines with a capital L. So heads up always specify your collection name or check your collection name in your MongoDB Shell/ MongoDB Atlas.
Second of all. Always check if the _ids your array/object that you want to populate are correct _ids that exist in your database. If they are non-existent or wrong the response would either contain empty array or even would return error.
For example I was adding this in the beginning when the error was occuring but those _ids were not existing (I had deleted them before but forgot) in my orderLines collection in the first place (you can still add _ids that are not existing if they are the correct _id structure so be aware)
Third of all. If you are using TypeScript there are three approaches that work:
After all of the above three things are taken in consideration what worked for me in the end was this approach:
And this is a part of the response I am getting just to showcase that both orderedline, productId and userId are being populated correctly
You defined
OrderLine
like this:Then, you specified
orderedlines
as an array ofOrderLine
:In your use case,
orderedlines
are an array ofObjectId
and not an array of objects with nested propertyorderlineId
. TypeScript probably do some sort of casting when defining a model.Try to change
orderedlines
to be an array ofObjectId
and try again?