sequelize / website

Our beloved website that contains all versions of our documentations and the API references.
https://sequelize.org
29 stars 154 forks source link

associations from official documentation example #292

Open eugene-matvejev opened 5 years ago

eugene-matvejev commented 5 years ago

What was unclear/insufficient/not covered in the documentation

I came from PHP, doctrine world, but now try understand sequlize, I struggle with associations, I tried to follow manual http://docs.sequelizejs.com/manual/associations.html

If possible: Provide some suggestion how we can enhance the docs

more examples

idea is to have more than one battlefield associated with each game. but only one game to each battlefield, e.g. one-to-many

#game.js
export default (sequelize, DataTypes) => {
    const model = sequelize.define(
        'Game',
        {
            id: {
                // type: DataTypes.UUID,
                type: DataTypes.INTEGER,
                primaryKey: true,
                autoIncrement: true,
            },
        },
        {
            tableName: 'games',
            timestamps: false,
        }
    );

    return model;
};
#battlefield.js
export default (sequelize, DataTypes) => {
    const model = sequelize.define(
        'Battlefield',
        {
            id: {
                // type: DataTypes.UUID,
                type: DataTypes.INTEGER,
                primaryKey: true,
                autoIncrement: true,
            },
            game: {
                // type: DataTypes.UUID,
                type: DataTypes.INTEGER,
                allowNull: false,
            }
        },
        {
            tableName: 'battlefields',
            timestamps: false,
        }
    );

    model.associate = function ({ Game, Battlefield, User }) {
        Game.hasMany(Battlefield, { foreignKey: 'game', sourceKey: 'id' });

        Battlefield.belongsTo(Game, { foreignKey: 'game', targetKey: 'id' });
    }

    return model;
};
#query:
                models.Battlefield.findAll({
                    include: [
                        {
                            model: models.Game,
                            where: {
                                id: gameId,
                            },
                        },
                    ],
                    raw: true,
                })
result: 
Game is not associated to Battlefield!

to overcome it, index.js is like very needed:

import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import { database as c } from '../../config/config';

const sequelize = new Sequelize(c.database, c.username, c.password, c);

const basename = path.basename(__filename);
const context = fs
    .readdirSync(__dirname)
    .reduce(
        (acc, file) => {
            if ((file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js')) {
                const model = sequelize['import'](path.join(__dirname, file));
                acc[model.name] = model;
            }

            return acc;
        },
        {}
    );

for (const name in context) {
    const model = context[name];

    if (model.associate) {
        model.associate(context);
    }
}

context.sequelize = sequelize;
context.Sequelize = Sequelize;

export default context;

it is unclear from docs, how to initiate models

papb commented 5 years ago

Thanks for the input! I will try to take a look later...

megamit commented 5 years ago

I just ran into this roadblock when using sequelize for the first time. Seeing eugenes solution helped me create my own Since you dont have to do the association exactly when you define it putting a next tick callback does the trick as it will get called before the database actually connects

const { Model } = require('sequelize')

module.exports = (sequelize, DataTypes) => {
  class Conversation extends Model {
    async advanceStage () {
      await this.increment('stage')
    }
    async getCurrentQuestion () {
      const Question = sequelize.models.questions.findByPk(this.question)
    }
  }
  Conversation.init({
    id: {
      type: DataTypes.INTEGER,
      autoIncrement: true,
      primaryKey: true
    },
    username: {
      type: DataTypes.STRING
    },
    stage: {
      type: DataTypes.INTEGER
    },
    roomId: {
      type: DataTypes.STRING
    }
  }, { sequelize });
  process.nextTick(() => {
    Conversation.belongsTo(sequelize.models.Campaign)
  })
  return Conversation
}
papb commented 5 years ago

@megamit Your trick with nextTick is too hacky. I don't recommend this...

github-actions[bot] commented 2 years ago

This issue has been automatically marked as stale because it has been open for 14 days without activity. It will be closed if no further activity occurs within the next 14 days. If this is still an issue, just leave a comment or remove the "stale" label. 🙂