Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure sequelize to return embedded array in a one-to-many association?

here is the deal:

I have two models - User and House
User has many houses
House belongs to a User

I've entered some dummy data and created a minimal express app to serve an api
I want to return a list of users and include each users houses.

the api endpoint looks like this:

router.get('/users', function(req, res,next) {
  models.User.findAll({
      include: [ models.House ],
      raw: true // returns result-set as a clean json...
  })
  .then(function(users) {
      d('num users found: ' + users.length);
      res.json(users);
  })
  .catch(function(err){
      d('DB ERROR: '+err.message);
      next(err);
  });

});

The default behavior of Sequelize is to return multiple instances of the same User data, each time with a different house data like so:

[
  {
    id: 1,
    first_name: "aa",
    last_name: "aaaaaa",
    email: "[email protected]",
    Houses.id: 1,
    Houses.description: "house 1 desc",
    Houses.user_id: 1
  },
  {
    id: 1,
    first_name: "aa",
    last_name: "aaaaaa",
    email: "[email protected]",
    Houses.id: 3,
    Houses.description: "house 3 desc",
    Houses.user_id: 1
  },
  {
    id: 2,
    first_name: "bb",
    last_name: "bbbbbb",
    email: "[email protected]",
    Houses.id: 2,
    Houses.description: "house 2",
    Houses.user_id: 2
  }
]

Can I get an array of houses embedded in the owning user?
Is there a way to configure Sequelize to return the data like so:

[
  {
    id: 1,
    first_name: "aa",
    last_name: "aaaaaa",
    email: "[email protected]",
    Houses:[
       {
          id: 1,
          description: "house 1 desc",
          user_id: 1
       },
       {
          id: 3,
          description: "house 3 desc",
          user_id: 1
       },
    ]
  },

  {
    id: 2,
    first_name: "bb",
    last_name: "bbbbbb",
    email: "[email protected]",
    Houses:[
       {
          id: 2,
          description: "house 2",
          user_id: 2
       }
    ]
  }
]

If the answer is no, can you recommend of a way to parse the data into such a structure?

The User Model:

module.exports = function(sequelize, DataTypes) {

  var User = sequelize.define('User', {

        first_name: DataTypes.STRING,
        last_name: DataTypes.STRING,
        email: DataTypes.STRING

    }, 
    {
      classMethods: {
        associate: function(models) {
          User.hasMany(models.House)
        }
      }
  });

  return User;
};

The house model:

module.exports = function(sequelize, DataTypes) {
  var House = sequelize.define("House", {
      description: DataTypes.TEXT
  }, 
  {
    classMethods: {
      associate: function(models) {
        House.belongsTo(models.User);
      }
    }
  });

  return House;
};
like image 663
Ajar Avatar asked Feb 27 '16 13:02

Ajar


2 Answers

I had a similar problem and just found a solution that seems to work in my case:

router.get('/users', function(req, res, next) {
  models.User.findAll({
      include: [ {model: models.House, as: 'houses'} ],
      raw: false // returns result-set as sequelize object...
  })
  .then(function(users) {
      users = users.get(); //turns sequelize object into json
      d('num users found: ' + users.length);
      res.json(users);
  })
  .catch(function(err){
      d('DB ERROR: '+err.message);
      next(err);
  });

});

Set raw to false (or let it default to that), then, anytime you need to get the raw json before the res.json, use users.get() ("users" now being a sequelize instance) and you can get the json of that sequelize object that is now an object with an array of its associations!

like image 194
Cordon Davies Avatar answered Nov 28 '22 12:11

Cordon Davies


 models.User.findAll({
      include: [ models.House ],
      nest: true
  })

add nest attribute to your query
remove raw true

for more related to issue
github-sequelize-issue 3885
stackoverflow-questions-61532849

like image 32
SANTHOSH.SJ Avatar answered Nov 28 '22 13:11

SANTHOSH.SJ