1

I am practicing my express.js skills by building a relational API and am struggling to populate keys in a schema.

I am building it so I have a list of properties, and those properties have units. The units have a propertyId key.

This is currently returning an empty array, whereas if i remove the populate({}) it returns an array of ObjectIds.

I've read a number of posts and some people solved this by using .populate({path: 'path', model: Model}); but this doesn't seem to be doing the trick. I think it might be the way I am adding a propertyId to the unit but I'm not sure. Can anyone see where I am going wrong? Any help will be massively appreciated.

Here are the schemas.

Property:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const PropertySchema = new Schema({
  title: {
    type: String,
    required: true
  },
  date: {
    type: Date,
    default: Date.now
  },
  units: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'unit'
    }
  ]
});

module.exports = Property = mongoose.model('property', PropertySchema);

Unit:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const UnitSchema = new Schema({
  title: {
    type: String,
    required: true
  },
  propertyId: {
    type: Schema.Types.ObjectId,
    ref: 'property'
  }
});

module.exports = Unit = mongoose.model('unit', UnitSchema);

I am then creating the unit like this:

-- api/properties/:id/units --
router.post('/:id/units', async (req, res) => {

  // Get fields from req.body
  const { title } = req.body;

  // Get current property
  const property = await Property.findById(req.params.id);

  try {

    // Throw error if no property
    if (!property) {
      return res.status(400).json({ msg: 'Property not found' });
    }

    // Create new unit
    const newUnit = new Unit({
      title,
      propertyId: req.params.id
    });

    // Add new unit to property's units array
    property.units.unshift(newUnit);

    // Save property
    await property.save();

    // Return successful response
    return res.status(200).json(property);

  } catch (error) {
    console.error(error.message);
    return res.status(500).send('Server error');
  }
});

And trying to populate in the GET request

-- /api/properties/:id/units --
const Unit = require('../../models/Unit');

router.get('/:id/units', async (req, res) => {
  const property = await Property.findOne({ _id: req.params.id }).populate({path: 'units', model: Unit});
  const propertyUnits = property.units;
  return res.status(200).json(propertyUnits);
});

If i remove the .populate({path: 'units', model: Unit});, I get a list of unit id's like this:

[
    "5ff7256cda2f5bfc1d2b9108",
    "5ff72507acf9b6fb89f0fa4e",
    "5ff724e41393c7fb5a667dc8",
    "5ff721f35c73daf6d0cb5eff",
    "5ff721eb5c73daf6d0cb5efe",
    "5ff7215332d302f5ffa67413"
]

2 Answers 2

0

I don't know, why you don't try it like this:

await Property.findOne({ _id: req.params.id }).populate('units')

I've been try that code above and it's working.

Note: Make sure to check your req.params.id is not null or undefined and make sure the data you find is not empty in your mongodb.

Updated: I've been try your code and it's working fine.

Sign up to request clarification or add additional context in comments.

3 Comments

If i just use .populate('units') it returns an empty array. Its working in that its saving the units to the Property, but its not populating the Property with the Unit object. In my database I currently have an array of just ObjectIds.
That's right, it's still working. If you need the screenshot, I can add it.
Its still only showing ObjectId's for me. Can you add a screen shot showing the unit objects inside the property?
0

The issue was caused by inconsistent naming and not saving the new created unit as well as the updated property.

I double checked all my schema exports and references and noticed I was using UpperCase in some instances and LowerCase in others, and saved the newUnit as well as the updated property in the POST request and it worked.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.