0

I am building a nodejs app, that stores the menus of the different restaurants. The schema is given below -

  var company = new Schema({
        company_name : String,
        categories : [category]
    });

  var category = new Schema({
        // id : Object,
        category_name : String,
        subCategories : [subCategory]
    });

    var subCategory = new Schema({
        subCategory_name : String,
        items : [item]

    });

    var item = new Schema({
        item : String,
        price : Number,
        currency : String

    });

module.exports = mongoose.model('Menu', company)

I have a rout in node app for example :

app.post("/:_company_id/:_category_id/:_sub_cat_id/", function(res,req){...})

using above method I want to insert/update the items so how do i do that.

Also while doing research I found that the mongoose does not support the nested array update. by using positional approach $ example categories.$.subCategories.$.items Cannot use this because mongoose does not support this.

Please help me with some other trick/hack which may help me in updating it. Thank you. If not than I have to move to some relational databases.

parwatcodes
  • 6,669
  • 5
  • 27
  • 39
bashIt
  • 1,006
  • 1
  • 10
  • 26

1 Answers1

0

Updating a nested array is as simple as updating the sub-category document and pushing the sub-categories ObjectID into the parent document. I put the rough steps at the bottom. Here is an example of the schema setup that allows for this.

A parent category can contain a reference to another schema as a subcategory. For example:

var companySchema = new Schema({
    company_name : String,
    categories : [{
        type: Schema.Types.Mongoose.ObjectId,
        ref: Category
    }]
 });

var categorySchema = new Schema({
    category_name : String,
    subCategories : //Similar to above to reference sub-categories
});

var category = Mongoose.Model('Category', categorySchema);

So the rough steps to then actually update the parent model with the sub-documents are:

  1. Query and return parent document whose callback...
  2. queries and returns child document/subdocument. Then,
  3. update the sub document as necessary (see the mongoose API for proper methods). Now,
  4. push the ObjectId of the subdocument (if it isn't in there all ready) into respective parent property. Finally,
  5. save sub document and parent document.

Here is a watered down example .

Company.findOne({company_name: "someUniqueCompanyName"}, function(err, foundCompany){
    if(err){
         console.log(err);
    }
    //This could also be a Category.create(...)
    Category.findOne({someProperty:"someUniqueValue"}, function(err, foundCategory){
        if(err){
            console.log(err);
        }


        foundCategory.name = "New Category Name"; //Update Category
        foundCategory.save(); //save category

        //if category doesn't exist in company then push it. More often 
        //than not you will be doing a Category.create and then pushing 
        //the newly created category into foundComapny
        foundCompany.categories.push(foundCategory._id);
        foundCompany.save();
    })
})

What this really allows you to do is populate these parent documents in the future by using the Sub-documents ObjectId.

About populate: http://mongoosejs.com/docs/populate.html

About Update methods : http://mongoosejs.com/docs/api.html

Brandon
  • 1,747
  • 2
  • 13
  • 22
  • Thanks for a quick response, could you please tell me more about **foundChild._id** from where you are getting the object **foundChild**. – bashIt Apr 16 '17 at 17:11
  • foundCategory.update({category_name: "newConcept"}) this doesn't woks :( @Brandon – bashIt Apr 16 '17 at 19:22
  • also there is a problem with **findByID**, callback doesn't trigger if the id is not present in the document. – bashIt Apr 16 '17 at 19:50
  • I'm sorry, foundChild was a typo. Also, I updated the above answer using "findOne" instead of "findById", and tried to make the example more specific to your question. I added some pseudo update code as well. – Brandon Apr 16 '17 at 20:39
  • In my example above we are not updating with a query, we are returning a found document with a query and then updating. To update with a mongoose query, you would do `Model.findOneAndUpdate()` so... `Category.findOneAndUpdate({category_name: "newConcept"}, {$set {propertyToUpdate: "newValue"}}, function(err, updatedCategory){...})` The APIs list the multitude of options you can do to extend this simple example. – Brandon Apr 16 '17 at 21:22
  • Thank you @Brandon this really helped me. thanks for the clear explanation and your precious time. – bashIt Apr 17 '17 at 17:58