Search code examples
node.jsmongodbmongoosemongoose-schema

Cannot populate Mongoose schema from req.body


I'm working with a complex data structure in MongoDB and using mongoose to handle the server-to-database communication.

In mongoose I have a schema defined like this:

var mongoose = require('mongoose')
var Schema = mongoose.Schema;

const timePeriodSchema = new mongoose.Schema({
    opensAt: {type: String, default: null},
    closesAt: {type: String, default: null}
});

const daySchema = new mongoose.Schema({
    closed: {type: Boolean, default: false},
    hours: [timePeriodSchema]
});

const weekSchema = new mongoose.Schema({
    monday: daySchema,
    tuesday: daySchema,
    wednesday: daySchema,
    thursday: daySchema,
    friday: daySchema,
    saturday: daySchema,
    sunday: daySchema,
});

const restaurantSchema = new mongoose.Schema({
    userId: {
        type: mongoose.Schema.Types.ObjectId,
        required: false,
        ref: 'User',
        default: null
    },
    name: {
        type: String,
        required: true,
        default: null
    },
    category: [String],
    type: [String],
    style: [String],
    cuisine: [String],
    customDescription: {
        type: String,
        required: false,
        default: null
    },
    address: {
        type: String,
        required: true,
        default: null
    },
    countryCode: {
        type: String,
        required: true,
        default: null
    },
    services: [String],
    photos: [Buffer],
    openingHours: weekSchema,
    phonePrefix: {
        type: String,
        required: true,
        default: null
    },
    phoneNumber: {
        type: String,
        required: true,
        default: null
    },
    website: {
        type: String,
        required: false,
        default: null
    },
    reservationMethods: [String],
    paymentMethods: [String],
    createdAt: {
        type: Date,
        required: true,
        default: Date.now,
    }
});

module.exports = mongoose.model('Restaurant', restaurantSchema)

And I try to create a new Restaurant with the following code:

saveRestaurant: function(req, res){
        Restaurant.findOne({
            address: req.body.address
        }, function(err, restaurant){
            if(err) throw err;
            if(restaurant){
                return res.status(500).send({success: false, key: 'addressUsed', title: res.__('requestFailedTitle'), msg: res.__('restaurantSaveAlreadyExistsErrorMsg')});
            }else{
                User.findOne({
                    email: req.body.userEmail
                }, function (err, user){
                    if(err){
                        throw err
                    }
                    if(user){
                        var restaurant = new Restaurant(req.body);
                        restaurant.userId = user._id;
                        restaurant.save(function(err, restaurant){
                            if(err) throw err;
                        });
                        return res.status(200).send({success: true, msg: res.__('saveSuccessResponse')});
                    }
                });
            }
        });
    }

And here is a sample of the req.body that the server receives:

{
  "userEmail": "example@gmail.com",
  "name": "My Restaurant",
  "category": [ "Café", "Pub" ],
  "type": [ "Ethnic Restaurant", "Fine Dining Restaurant" ],
  "style": [ "Elegant" ],
  "cuisine": [ "Haute" ],
  "customDescription": "This is a custom description",
  "address": "Piazza di Spagna, Piazza di Spagna, Rome, Metropolitan City of Rome, Italy",   
  "countryCode": "IT",
  "services": [ "Handicap", "Restroom" ],
  "photos": [],
  "openingHours": {
    "Monday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]},
    "Tuesday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]},
    "Wednesday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]},
    "Thursday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]},
    "Friday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]},
    "Saturday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]},
    "Sunday": { "closed": true, "hours": [
        {"opensAt": "11:00", "closesAt": "17:00"}
    ]}
  },
  "phonePrefix": "+39",
  "phoneNumber": "1234567890",
  "website": "asdfg.it",
  "reservationMethods": [ "Phone" ],
  "paymentMethods": [ "Cash", "Card" ]
}

The problem is that the restaurant created has all the fields set perfectly, except for the nested openingHours field.

In the openingHours field only the _id of an object is stored and nothing else.

It seems that mongoose is not able to retrieve and populate the nested schemas.

However I have read that apparently it should be able to. Anyone have any idea of what I am doing wrong?

I don't want to use separate collections and link them via _id as it would result in too many useless collections; I would like to have everything in the same collection.

Here below is a screenshot of what is actually saved in MongoDB: MongoDB document


Solution

  • Your definition of days in a schema and days in data are in different cases:

    all small letters

    const weekSchema = new mongoose.Schema({
        monday: daySchema,
        tuesday: daySchema,
        wednesday: daySchema,
        thursday: daySchema,
        friday: daySchema,
        saturday: daySchema,
        sunday: daySchema,
    });
    

    and in data the first letter is capital:

        "Monday": { "closed": true, "hours": [
            {"opensAt": "11:00", "closesAt": "17:00"}
        ]},
        "Tuesday": { "closed": true, "hours": [
            {"opensAt": "11:00", "closesAt": "17:00"}
        ]},
        "Wednesday": { "closed": true, "hours": [
            {"opensAt": "11:00", "closesAt": "17:00"}
        ]},
        ...