Sequelize associations are not functioning optimally as expected

Trying to display a nested relationship:

Cat.hasMany(legs)

Leg.belongsTo(cat)

Leg.hasOne(paw)

paw.hasMany(leg)

This is the Cat Model:

module.exports = (sequelize, DataTypes) => {
      const Cat = sequelize.define('Cat', {
        userId: {
          type: DataTypes.STRING,
        },
      }, {});

      Cat.associate = function (models) {
        Cat.hasMany(models.Leg, {
          foreignKey: 'catId',
          as: 'legs',
        });
      };
      return Cat;
    };
    

The Legs Model:

module.exports = (sequelize, DataTypes) => {
      const Leg = sequelize.define('Leg', {
        originalValue: DataTypes.JSON,
        newValue: DataTypes.JSON,
        legId: DataTypes.INTEGER,
        objectId: DataTypes.INTEGER,
        pawId: DataTypes.INTEGER,
      }, {});

      Leg.associate = function (models) {
        Leg.belongsTo(models.Cat, {
          foreignKey: 'LegId',
          onDelete: 'CASCADE',
        });
        Leg.hasOne(models.Paw, {
          foreignKey: 'pawId',
        });
      };
      return Leg;
    };
    

The Paw model

module.exports = (sequelize, DataTypes) => {
      const Paw = sequelize.define('Paw', {
        pawType: DataTypes.STRING,
      }, {});
      Paw.associate = function (models) {
        Paw.hasMany(models.Leg, {
          foreignKey: 'pawId',
          as: 'paws',
        });
      };
      return Paw;
    };
    

When querying the Cat Table, the code currently displays:

[
        {
            "id": 1,
            "userId": "2wdfs",
            "createdAt": "2018-04-14T20:12:47.112Z",
            "updatedAt": "2018-04-14T20:12:47.112Z",
            "legs": [
                {
                    "id": 1,
                    "catId": 1,
                    "pawId": 1,
                    "createdAt": "2018-04-14T20:12:54.500Z",
                    "updatedAt": "2018-04-14T20:12:54.500Z"
                }
            ]
        }
    ]
    

I want to include the pawType from the paws table like this:

[
        {
            "id": 1,
            "userId": "2wdfs",
            "createdAt": "2018-04-14T20:12:47.112Z",
            "updatedAt": "2018-04-14T20:12:47.112Z",
            "legs": [
                {
                    "id": 1,
                    "catId": 1,
                    "paws" : [
                        {
                            "id": 1,
                            "pawType": "cute"
                        }
                    ],
                    "createdAt": "2018-04-14T20:12:54.500Z",
                    "updatedAt": "2018-04-14T20:12:54.500Z"
                }
            ]
        }
    ]
    

Query used to retrieve Cats:

return Cat.findAll({ include: [{ model: Leg, as: 'legs',include [{model: Paw,}], }], })
    

Error received:

{ SequelizeDatabaseError: column legs->Paw.pawId does not exist
    { error: column legs->Paw.pawId does not exist
    

Full SQL command:

sql: 'SELECT "Cat"."id", "Cat"."userId", "Cat"."createdAt", "Cat"."updatedAt", "legs"."id" AS "legs.id", "legs"."originalValue" AS "legs.originalValue", "legs"."newValue" AS "legs.newValue", "legs"."catId" AS "legs.catId", "legs"."objectId" AS "legs.objectId", "legs"."pawId" AS "legs.pawId", "legs"."createdAt" AS "legs.createdAt", "legs"."updatedAt" AS "legs.updatedAt", "legs->Paw"."id" AS "legs.Paw.id", "legs->Paw"."paw" AS "legs.Paw.paw", "legs->Paw"."pawId" AS "legs.Paw.pawId", "legs->Paw"."createdAt" AS "legs.Paw.createdAt", "legs->Paw"."updatedAt" AS "legs.Paw.updatedAt" FROM "Cats" AS "Cat" LEFT OUTER JOIN "Legs" AS "legs" ON "Cat"."id" = "legs"."catId" LEFT OUTER JOIN "Paws" AS "legs->Paw" ON "legs"."id" = "legs->Paw"."pawId";' },
    

Answer №1

There are several issues that need to be addressed one by one.

1) Models When you do not specify a primaryKey, sequelize automatically adds an id column for you. Therefore, the legId column is redundant and unnecessary.

Additionally, when associating models, the foreignKey reference is automatically added for you, so there is no need to declare the pawId column.

Therefore, the modified version of the Legs.js file should look like this:

module.exports = (sequelize, DataTypes) => {
  var Leg = sequelize.define('Leg', {
    originalValue: DataTypes.JSON,
    newValue: DataTypes.JSON,
    objectId: DataTypes.INTEGER // purpose unclear 
  })
  Leg.associate = function (models) {
    // associations
  }
  return Leg
}

The modifications above result in the following columns being displayed in pgAdmin: https://i.stack.imgur.com/VNsLc.png

2) Associations

The association below will cause an error due to cyclic dependency:

Leg.hasOne(Paw)
Paw.hasMany(Leg)

Unhandled rejection Error: Cyclic dependency found. Legs is dependent of itself.
Dependency chain: Legs -> Paws => Legs

For each Leg to have one Paw, the following adjustments are suggested:

Leg.associate = function (models) {
  // Leg.belongsTo(models.Cat)
  Leg.hasOne(models.Paw, {
    foreignKey: 'pawId',
    as: 'paw'
  })
}

Paw.associate = function (models) {
  Paw.belongsTo(models.Leg, {
    as: 'leg' // revised for clarity
    foreignKey: 'pawId'
  })
}

3) Foreign Keys

Leg.belongsTo(models.Cat, {
  foreignKey: 'catId', // ensure consistency
  onDelete: 'CASCADE'
})

Cat.hasMany(models.Leg, {
  foreignKey: 'catId', // ensure consistency
  as: 'legs'
})

4) Eager Loading

When eager loading nested associations, remember to use the include option and provide aliases using as:

Cat.findAll({
  include: [{
    model: Leg,
    as: 'legs', // Cat.legs 
    include: [{
      model: Paw,
      as: 'paw' // Leg.paw instead of Leg.pawId
    }]
  }]
})

With this setup and query, the output will be as follows:

[
  {
    "id": 1,
    "userId": "1",
    "createdAt": "2018-04-15T11:22:59.888Z",
    "updatedAt": "2018-04-15T11:22:59.888Z",
    "legs": [
      {
        "id": 1,
        "originalValue": null,
        "newValue": null,
        "objectId": null,
        "createdAt": "2018-04-15T11:22:59.901Z",
        "updatedAt": "2018-04-15T11:22:59.901Z",
        "catId": 1,
        "paw": {
          "id": 1,
          "pawType": null,
          "createdAt": "2018-04-15T11:22:59.906Z",
          "updatedAt": "2018-04-15T11:22:59.906Z",
          "pawId": 1
        }
      }
    ]
  }
]

Extra

If you want to model a many-to-many relationship between Paw and Leg, you can define it as shown below:

Paw.associate = function (models) {
  Paw.belongsToMany(models.Leg, {
    foreignKey: 'pawId',
    through: 'PawLegs' // ensure you define the through join table
  })
}

This approach is a more appropriate way of implementing what was previously attempted with the code snippet:

Leg.hasOne(paw)
paw.hasMany(leg)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issues have been encountered with activating checkboxes on Internet Explorer while utilizing ASP.NET CheckBox controls

I'm facing an issue with an HTML form that includes two disabled checkboxes and an image with an onclick event intended to display a popup and enable the checkboxes: <input id="chk1" type="checkbox" disabled="disabled" /> <input id="chk2" ty ...

Navigating through the maze of ES6 imports and dealing with the complexities

Currently, I am delving into React and creating my own components. However, the issue of project organization has arisen. Here is the structure of my project: Project_Folder - Components - Form - index.js - form.less - package.js ...

mentioning a JSON key that includes a period

How can I reference a specific field from the JSON data in Angular? { "elements": [ { "LCSSEASON.IDA2A2": "351453", "LCSSEASON.BRANCHIDITERATIONINFO": "335697" }, { "LCSSEASON.IDA2A2": "353995", "LCSSEASON.BRANCHIDITER ...

Conceal YouTube upon opening any model or light box

I have a YouTube video in the center of my page, and when I click on any link from the side navigation, a lightbox appears. However, in IE, the lightbox is behind the YouTube video. I have tried setting the Z-index, but it doesn't seem to work. Is the ...

Are there any creative methods for structuring Node.js Alexa code efficiently?

I'm looking for a more organized approach to managing my Node.js Alexa code. With the increasing number of intents in my interaction model, the lines of code in my lambda's index.js have become difficult to manage. Can someone provide an example ...

Looking for assistance in showcasing information retrieved from an external API

I've been working with an API and managed to fetch some data successfully. However, I'm having trouble displaying the data properly in my project. Can anyone provide assistance? Below is a screenshot of the fetched data from the console along wit ...

The material-ui library always registers Event.ctrlKey as true

When using the Table Component from the material-ui library, I encountered an issue with the multiSelectable feature. Setting the value of multiSelectable to true allows for multiple selections, but the behavior is not what I expected. By default, the sel ...

JavaScript truthy values referring to numbers

According to the rules outlined below: Falsy: false 0 (zero) '' or "" (empty string) null undefinded NaN (e.g. the result of 1/0) Truthy: Anything else I'm puzzled as to why, in the tests that follow, only the number 1 is considered "tr ...

axios encountering a 400 bad request error during the get request

I've hit a roadblock for some time now while trying to make a call to my API to fetch data using the GET method. I keep getting a 400 bad request error in Postman, even though I am able to successfully retrieve the data with a status code of 200. I ha ...

What's the best way to launch multiple Node.js services within a single Docker Compose configuration?

I am currently working on setting up two docker containers running MongoDB and Postgres. Both of these containers are functioning properly. My goal is to create two services (node.js instances) that will connect from separate containers in order to query a ...

The entry '0-0' already exists for the key 'local_part', please enter a unique value

Creating a simple API to handle GET, POST, DELETE, and UPDATE requests. The GET method is functioning correctly, but encountering an issue with the POST method. When attempting to post data, an error is being encountered: error: Error: ER_DUP_ENTRY: ...

Organizing JSON keys based on their values using Typescript

In the context of a main JSON structure represented below, I am interested in creating two separate JSONs based on the ID and Hobby values. x = [ {id: "1", hobby: "videogames"}, {id: "1", hobby: "chess"}, {id: "2", hobby: "chess ...

Comparing AngularJS $interpolate with $filter

AngularJS offers different tools for manipulating data displayed to users. While $filter is commonly used for formatting data, $interpolate enables real-time updates within a text string. Do $interpolate and $filter have any connection? How do they differ ...

Update the URL and content in Django dynamically

When accessing a json response from my Django backend via the URL /inbox/<str:username>, all messages in the conversation with that user are retrieved. The issue arises on the inbox page, where both threads and chatbox are displayed together, similar ...

Encountering an issue when implementing a conditional check within the .map() function utilizing ES6 syntax

I'm struggling to assign only the object that contains an iban value to the list in the code snippet below. I haven't been able to fix this issue on my own and would appreciate some assistance. This.ibanList = this.data.map( (value, in ...

Create dynamic connections between animated sprites using Three.js

I am attempting to insert lines between animated sprites, similar to the example provided. Despite trying various solutions, I have been unsuccessful in creating either a dynamic or static line between these animated sprites. Is it feasible to generate a d ...

Circular dependency in Typescript/Javascript: Attempting to extend a class with an undefined value will result in an error,

Query Greetings, encountering an issue with the code snippet below: TypeError: Super constructor null of SecondChild is not a constructor at new SecondChild (<anonymous>:8:19) at <anonymous>:49:13 at dn (<anonymous>:16:5449) ...

<use> - SVG: Circles with different stroke properties

Why is the stroke of both <use> elements being ignored here? The stroke color of <circle> is set to blue, which is also appearing on both <use> elements. Why? I am trying to set different stroke colors for all three of these elements, bu ...

Utilize the v-if directive with nested object properties for dynamic conditional rendering

I need to verify if the item object has a property called 'url' set. If it's not present, I would like to display a placeholder image. Here is an example of what I want to achieve: <img v-if="item.relationships.main ...

What is the best way to create a dynamic icon using React and TypeScript?

Excuse me, I am new to using React and TypeScript. I'm having trouble getting the icon to change based on the status in AppointmentType. The body color is working fine, but the icons are not changing. Can someone please help me solve this issue? const ...