Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
368 views
in Technique[技术] by (71.8m points)

node.js - How to implement many to many association in sequelize

I have two tables: Books and Articles with a many-to-many relationship between them. Joining table is BookArticles.

models/books.js

module.exports = function(sequelize, DataTypes) {
  return Food = sequelize.define("Book", {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      allowNull: false,
      autoIncrement: true,
      unique: true
    }
  });
}

models/articles.js

module.exports = function(sequelize, DataTypes) {
  return Food = sequelize.define("Article", {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      allowNull: false,
      autoIncrement: true,
      unique: true
    }
  });
}

models/bookArticles.js

module.exports = function(sequelize, DataTypes) {
  return Food = sequelize.define("BookArticles", {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      allowNull: false,
      autoIncrement: true,
      unique: true
    },
   bookId: {
      type: DataTypes.INTEGER,
      references: 'Book',
      referencesKey: 'id',
      allowNull: false
    },
    ArticleId: {
      type: DataTypes.INTEGER,
      references: 'Article',
      referencesKey: 'id',
      allowNull: false
    },
  });
}

And models/index.js

m.BookArticles.belongsTo(m.Book);
m.Book.hasMany(m.Article, {through: m.BookArticles});


m.BookArticles.belongsTo(m.Article);
m.Article.hasMany(m.Books, {through: m.BookArticles});

but I could not get book articles

How can I get it ??

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Sequelize Association Cheatsheet

Updated for Sequelize v2/3/4/5

Generally I think the problems are that we are confused about what tables created, and what methods are gained by associations.

Note: Defining foreignKey or cross table name are optional. Sequelize automatically creates it, but defining it allows coders to read the models and find out what the foreign keys/cross table names are, instead of guessing or needing to access the database.

TLDR;

O:O

// foreign key has to be defined on both sides.
Parent.hasOne(Child, {foreignKey: 'Parent_parentId'})
// "Parent_parentId" column will exist in the "belongsTo" table.
Child.belongsTo(Parent, {foreignKey: 'Parent_parentId'})

O:M

Parent.hasMany(Child, {foreignKey: 'Parent_parentId'})
Child.belongsTo(Parent, {foreignKey: 'Parent_parentId'})

N:M

Parent.belongsToMany(
    Child, 
    {
        // this can be string (model name) or a Sequelize Model Object Class
        // through is compulsory since v2
        through: 'Parent_Child',

        // GOTCHA
        // note that this is the Parent's Id, not Child. 
        foreignKey: 'Parent_parentId'
    }
)

/*
The above reads:
"Parents" belongs to many "Children", and is recorded in the "Parent_child" table, using "Parents"'s ID.
*/

Child.belongsToMany(
    Parent, 
    {
        through: 'Parent_Child',

        // GOTCHA
        // note that this is the Child's Id, not Parent.
        foreignKey: 'Child_childId'
    }
)

Why the verbose "Parent_parentId" and not just "parentId"? This is to make it obvious that it's a foreign key that belonged to "Parent". In most cases it's okay to just use the more succinct "parentId".*

Associations gives you 2 functionality: (1) Eager loading and (2) DAO Methods:

1. Include (Eager loading)

DB.Parent.findOne({ 
    where: { id: 1 },
    include: [ DB.Child ]
}).then(parent => {

    // you should get `parent.Child` as an array of children. 

})

2. Methods gained by hasOne(), hasMany() and belongsTo()/belongsToMany()

Associations give the Data Access Object (DAO) methods:

hasOne():

In setting a Parent.hasOne(Child), methods available to parent DAO instance:

DB.Parent.findOne({ where: { id: 1 } }).then(parent => {

    // `parent` is the DAO
    // you can use any of the methods below:
    parent.getChild
    parent.setChild
    parent.addChild
    parent.createChild
    parent.removeChild
    parent.hasChild

})
hasMany():

In setting a Parent.hasMany(Child), methods available to parent DAO instance:

parent.getChildren,
parent.setChildren,
parent.addChild,
parent.addChildren,
parent.createChild,
parent.removeChild,
parent.hasChild,
parent.hasChildren,
belongsTo()/belongsToMany:

In setting a Child.belongsTo(Parent), methods available to child DAO instance:

child.getParent,
child.setParent,
child.createParent,

//belongsToMany
child.getParents,
child.setParents,
child.createParents,

You can also have multiple relationships

Natural Parents/Children
// a parent can have many children
Parent.belongsToMany(Child, {
    as: 'Natural',
    through: 'Parent_Child',
    foreignKey: 'Parent_parentId'
})
// a child must at least have 2 parents (natural mother and father)
Child.belongsToMany(Parent, {
    as: 'Natural',
    through: 'Parent_Child',
    foreignKey: 'Child_childId'
})
Foster Parents/Children
Parent.belongsToMany(Child, {
    as: 'Foster',
    through: 'Parent_Child',
    foreignKey: 'Parent_parentId'
})

Child.belongsToMany(Parent, {
    as: 'Foster',
    through: 'Parent_Child',
    foreignKey: 'Child_childId'
});

The above will create the Parent_Child cross table, with NaturalId and FosterId.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...