Search code examples
node.jsmongodbsails.jspopulatesails-mongo

Deep associations in sails mongo using populate method?


I am new to sails.js and I am using "sails.js with Mongodb". I am having problem with deep associations using populate in my sails app.

I have a relationship like this:

 Category has many to many relationship with Article.

 City has one to many relationship with Areas.

 Article has one to one relationship with City and Areas.

Category.js

module.exports = {

schema: true,

attributes: {

    //add referecnce to other article
    Articles: {
            collection: 'Article', 
            via:'ref_category_id' 
      },

    category_name: { 
        type:'string',  
        required: true, 
        unique: true },
  }
};

Article.js

module.exports = {

schema: true,

attributes: {

       //adding reference to category
        ref_category_id: {
                    collection:'Category',
                    via:'Articles'
         },

    //adding reference to city
     ref_city_id: {
                    model:'City'
       },

    //add a reference to area
         ref_area_id: {
                  model:'Areas'
        },

      //adding reference to tags
      tags: {
           collection: 'Tag', 
           via:'articles'
       },

      title:{ type:'string',required:true},

      blurb: { type: 'string'},

      description:{ type:'string'}
    }
 }; 

City.js

module.exports = {

        schema: true,

        attributes: {


        Areas: {
                collection: 'Areas', 
                via:'ref_city_id'
        },

         ref_article_id:{
                    model:'Article'
         },


        city_name: { type:'string',
                   required:true,
                   unique:true }
    }
 };

Areas.js

 module.exports = {

   schema: true, 

   attributes: {

        area_name: { type:'string',required:true},

        latitude: { type:'float'},

        longitude: { type:'float'},

        ref_city_id: {
                model: 'City' 
        },

        ref_article_id:{
             model:'Article'
         }

     }
 };

Tag.js

   module.exports = {

      schema:false,

      attributes: {

         //adding reference to article 
          articles: {
                  collection: 'Article', 
                  via:'tags'
          },

      tag_name:{type:'string',
                required:true,
                unique:true
         }
     }
  };

CategoryController.js

  searchCategory: function(req, res, next) {

    var category_name = req.param('category_name');

    Category.find({category_name:{'like': '%'+category_name+'%'}}).populate('Articles').exec(function(err, category) 
    {

        if(err)
        {
         return res.json({'status':486,'status_message':'Server Error'});
        }
        else
        { 
            if(category.length > 0)
            {
                 var c = parseInt(category[0].Articles.length,10);

                console.log(c);
                var i = parseInt('0',10);

                for (i=0; i<c; i++)
                {
                    console.log('i value in loop = ' + i);
                    Article.find({id:category[0].Article[i].id}).populateAll().exec(function(err,article_info) {
                        if(err)
                        {
                            return res.send(err);
                        }
                        else
                        {
                            console.log(article_info);
                            console.log('-------------------------------------------');

                            res.json(article_info); 
                            console.log(' I value = ' + i); 
                        }
                    }); 

                } 
                //console.log(category);
                //return res.json({'status':479,'status_message':'Success..!!','category_info':category});
            }
            else
            {
                return res.json({'status':489,'status_message':'failure..!! No categories found..!!'});
            }
        }
    });
}

POSTMAN Request:

 http://localhost:1337/category/searchCategory

 {"category_name":"travel"}

This is my json response: Here I am getting only article which is mapped with category. but i wanted to display the values of city, areas and tags which are mapped to article.

  {
   "status": 479,
   "status_message": "Success..!!",
   "category_info": [
     {
        "Articles": [
            {
                "ref_city_id": "55a766d0a29811e875cb96a1",
                "ref_area_id": "55a78b69578393e0049dec43",
                "title": "title",
                "blurb": "blurb",
                "description": "Description",
                "createdAt": "2015-07-16T12:36:36.778Z",
                "updatedAt": "2015-07-16T12:48:20.609Z",
                "id": "55a7a55439ace79e0512269d"
            },
        ],
        "category_name": "Cooking ",
        "id": "55a6b26aee9b41de747547bb",
        "createdAt": "2015-07-15T19:20:10.670Z",
        "updatedAt": "2015-07-15T19:20:10.670Z"
    }
  ]
}

How to do the deep nested associations using populate? or Is any other way to achieve this?

Please Can anyone help me to achieve this.

Thanks in advance.


Solution

  • Yes, there is another way to do this.

    Make sure you require the following npm module.

    var nestedPop = require('nested-pop');
    

     

    searchCategory: function(req, res, next) {
      var category_name = req.param('category_name');
      Category.find({category_name:{'like': '%'+category_name+'%'}})
      .populate('Articles')
      .exec(function(err, category) {
        if(err) return res.json({'status':486,'status_message':'Server Error'});
        if(category.length > 0) {
          var c = parseInt(category[0].Articles.length,10);
          console.log(c);
          var i = parseInt('0',10);
          for (var i = 0; i < c; i++) {
            console.log('i value in loop = ' + i);
            Article.find({id:category[0].Article[i].id})
            .populateAll()
            .exec(function(err, article_info) {
              if(err) return res.send(err);
              return nestedPop(article_info, {
                ref_city_id: {
                  as: 'City',
                  populate: [
                    'things',
                    'you',
                    'want',
                    'to',
                    'populate',
                    'for',
                    'city'
                  ],
                },
                ref_area_id: {
                  as: 'Area', // or Areas (whatever the model name is)
                  populate: [
                    'things',
                    'you',
                    'want',
                    'to',
                    'populate',
                    'for',
                    'area'
                  ]
                }
              }).then(function(article_info) {
                console.log(article_info);
                console.log('------------------------------------------');
                res.json(article_info); 
                console.log(' I value = ' + i);
              });
            }); 
          }
        } else {
          return res.json({'status':489,'status_message':'failure..!! No categories found..!!'});
        }
      });
    }
    

    Go to https://www.npmjs.com/package/nested-pop for more documentation.