skip to Main Content

I’m using Mongoose and NodeJS and I want to populate products.

const result = await orderModel.find({}).populate({
        path: 'products',
        model: 'products',
        select: {
          quantity: 1,
          unit: 1,
          product: 1
        },
        populate: {
          path: 'product',
          model: 'products',
          select: { type: 1, name: 1 }
        }
      });
      console.log('result', result);

this is the orderSchema:

const orderSchema = new mongoose.Schema({
 name: {
   type: String,
   required: false
 },
 products: [
       {
         product: { type: ObjectId, ref: 'products', required: false },
         quantity: { type: Number, required: false, default: 0 },
         unit: { type: String, required: false, default: '' }
       }
     ]
},
{
  timestamps: true
});
const orderModel = mongoose.model('orders', orderSchema);

the productSchema:

const productSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true
    },    
   type: {
     type: String,
     required: true
   }
}, { timestamps: true });
const productModel = mongoose.model('products', productSchema);

the data in database look like this:

[
  {
    "_id": {
      "$oid": "64e8b34b24bf0243bc87fa82"
    },
    "name": "ORDER 1",
    "products": [
      {
        "quantity": 100,
        "unit": "kg",
        "_id": {
          "$oid": "64e8d05a1be39f48906dec4b"
        },
        "product": {
          "$oid": "64e8b34724bf0243bc87fa2f"
        }
      }
    ],
    "createdAt": {
      "$date": {
        "$numberLong": "1692971851401"
      }
    },
    "updatedAt": {
      "$date": {
        "$numberLong": "1692979290410"
      }
    },
    "__v": 0
  }
]

I got this error:

Cannot read properties of null (reading ‘populated’)

TypeError: Cannot read properties of null (reading ‘populated’)
at markArraySubdocsPopulated (C:UsersuserOneDriveDocumentsbackendbackendNodeJS –
Copienode_modulesmongooselibhelperspopulatemarkArraySubdocsPopulated.js:41:18)
at assignVals (C:UsersuserOneDriveDocumentsbackendbackendNodeJS –
Copienode_modulesmongooselibhelperspopulateassignVals.js:195:7)
at _assign (C:UsersuserOneDriveDocumentsbackendbackendNodeJS – Copienode_modulesmongooselibmodel.js:5119:3)
at _done (C:UsersuserOneDriveDocumentsbackendbackendNodeJS – Copienode_modulesmongooselibmodel.js:4931:9)
at _next (C:UsersuserOneDriveDocumentsbackendbackendNodeJS – Copienode_modulesmongooselibmodel.js:4919:7)
at C:UsersuserOneDriveDocumentsbackendbackendNodeJS – Copienode_modulesmongooselibmodel.js:5028:5
at C:UsersuserOneDriveDocumentsbackendbackendNodeJS –
Copienode_modulesmongooselibmodel.js:5

353:18
at process.processTicksAndRejections (node:internal/process/task_queues:77:11)

I tried my code with two users data one works fine and the othrer throw the error.

3

Answers


  1. Chosen as BEST ANSWER

    If the products in the database are like this "products": [null]

    I got the error

    Cannot read properties of null (reading 'populated')

    I changed to "products": [] and it worked.


  2. Looks like mongoose cannot find the document that should be populated. It could be happening because of the way you have defined the ref property in your orderSchema. The ref property should match the model name for the referenced schema. In your case the model name for the productSchema is ‘products’, but it should be singular, not plural. I am assuming you have exported model as product, not products. If this is indeed the case then you can make the follwoing changes and try.

    product: { type: mongoose.Schema.Types.ObjectId, ref: 'product', required: false }
    

    Also in the populate method use the actual model name defined using mongoose.model.

    const result = await orderModel.find({}).populate({
      path: 'products',
      model: 'products', // Should be 'product'
      select: {
        quantity: 1,
        unit: 1,
        product: 1
      },
      populate: {
        path: 'product',
        model: 'products', // Should be 'product'
        select: { type: 1, name: 1 }
      }
    })
    
    Login or Signup to reply.
  3. You are facing this problem due to wrong usage of populate method.

    In your models, orderModel has only a reference to productModel on field orderModel.products.product. You want to populate each orders’ products’ product field.

    To accomplish this you have this code:

    const result = await orderModel.find({}).populate({
      path: 'products',
      model: 'products',
      select: {
        quanity: 1,
        unit: 1,
        product: 1
      },
      populate: {
        path: 'product',
        model: 'products',
        select: { type: 1, name: 1 }
      }
    });
    

    This code tries to populate field (or path) products in your orderModel objects but products field is an array of objects and is not a reference to another model that have the following structre:

    {
      product: { type: ObjectId, ref: 'products', required: false },
      quantity: { type: Number, required: false, default: 0 },
      unit: { type: String, required: false, default: '' }
    }
    

    As you can see, each element in products field/array is an object. You need to populate product field in each element. To do that, your code should be changed into the following code:

    const result = await orderModel.find({}).populate({
      path: 'products.product',
      model: 'products'
    });
    

    Since the referenced model is specified in your orderSchema, you can shorten the code like this:

    const result = await orderModel.find({}).populate('products.product');
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search