0

I'm having hard times with the mongoose relashionship system. Here are my schemes:

const mongoose = require('mongoose');


const RecipeSchema = mongoose.Schema({
  Title: { type: String },
  Description: { type: String },
  Complaints: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Complaint' }]
}); 

const Recipe = mongoose.model('Recipe', RecipeSchema);


const ComplaintSchema = mongoose.Schema({
  Recipe  : { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
  Message: { type: String }
});

const Complaint = mongoose.model('Complaint', ComplaintSchema);

And here are how I'm saving my data:

var recipeEntity = new Recipe({ 
    Title: request.body.Title,
    Description: request.body.Description
});

recipeEntity.save();


var complaintEntity= new Complaint({ 
    Message: request.body.Message.trim(),
    Recipe: mongoose.Types.ObjectId(request.body.Message.RecipeId);
});

complaintEntity.save();

So far, so good... at least to me!

And now, when I try to list the recipes with the complaints, I just got an empty array of complaints:

Recipe
    .find()
    .populate('Complaints') 
    .exec(callback);

And here is the json result:

[{
    "Id": "595fe6f89d63700011ee144d",
    "Title": "Chocolate Cake",
    "Description": "aaaa bbb cc d"
    "Complaints": []
}]

So, what am I missing here? tks for your support

Eduardo Spaki
  • 1,128
  • 1
  • 8
  • 18

2 Answers2

1

I am going to assume that you are not saving both recipe and complaint during the same call. That would not make any sense: everytime you make a complaint, you wouldn't make a recipe too.

When you create a complaint, you need to save its associated recipe's ObjectId AND also add/push the complaint's ObjectId into the associated recipe's complaints.

If you are following resource naming conventions, you would have something like:

// get recipes including complaints
app.get('/recipes', function (req, res) {
    Recipe.find().populate('Complaints').exec(function (err, recipes) {
        console.log(recipes);
    });
});

// add recipe
app.post('/recipes', function (req, res) {
    var recipe = new Recipe(req.body); // simplified
    recipe.save(function (err) {
        if (err)
            return res.send(err);    
        res.send('ok');
    });
});

// add complaint for recipe
app.post('/recipes/:recipeID/complaints', function (req, res) {

    // we query recipe bc we need it after
    Recipe.findById(req.params.recipeID, function (err, recipe) {
        if (err)
            return res.send(err);
        if (!recipe)
            return res.send('No recipe found');

        // add complaint
        var complaint = new Complaint(req.body);
        complaint.Recipe = recipe._id; // add reference in one direction
        complaint.save(function (err) {
            if (err)
                return res.send(err);

            // update recipe
            recipe.Complaints.push(complaint._id); // add reference in other direction
            recipe.save(function (err) {
                if (err)
                    return res.send(err);    
                res.send('ok');
            });
        });
    });

})

I think this is a good read: many to many relationship with nosql (mongodb and mongoose).

Mikey
  • 6,728
  • 4
  • 22
  • 45
1

OK, how I had to save the record in the reference too, I adopted this approach:

RecipeSchema.pre('remove', function(next) { 
    Complaint.remove({ "Recipe" : this._id }).exec();
    next();
});

ComplaintSchema.pre('remove', function(next) {
    Recipe.findById(this.Recipe).exec((error, item) => {
      var index = item.Complaints.indexOf(item.Complaints.find(e => e._id == this._id));
      item.Complaints.splice(index, 1);
      item.save(() => { next(); });
    });
});

ComplaintSchema.pre('save', function(next) {
    Recipe.findById(this.Recipe).exec((error, item) => {
      item.Complaints.push(this);
      item.save(() => { next(); });
    });
});

using this trigger/event available on the mongo schemas. That worked perfectly!

Eduardo Spaki
  • 1,128
  • 1
  • 8
  • 18