Многие ко многим ссылаются на себя в продолжении в Twitter, как веб-приложение

#mysql #reactjs #sequelize.js #associations

#javascript #node.js #База данных #многие ко многим #sequelize.js

Вопрос:

Я пытаюсь создать веб-приложение для блога в качестве упражнения для понимания ORM и Sequelize в частности. Мне удалось довольно легко сформировать отношения между сообщениями и комментариями, пользователями и сообщениями. Никаких проблем нет. Ужас начинается, когда я пытаюсь связать пользователей с пользователями как подписчиков, а пользователей с пользователями как подписчиков. Я также хочу, чтобы можно было следить за собой.

Я пробовал что-то вроде этого:

   const User = sequelize.define('user', {
    firstName: {
      type: Sequelize.STRING
    },
    lastName: {
      type: Sequelize.STRING
    },
    email: {
      type: Sequelize.STRING
    },
    password: {
      type: Sequelize.STRING
    },
    activated: {
      type: Sequelize.BOOLEAN
    }
  })
User.belongsToMany(User, {as: "Follower", foreignKey: "FollowerId", through: "Follower_Followeds"})
User.belongsToMany(User, {as: "Followed", foreignKey: "FollowedId", through: "Follower_Followeds"})
 

И установить отношения:

 app.post("/followhandler", function(req, res) {
    let userId = req.session.userId
    let followId = req.body.followId

    User.findById(userId)
    .then( currentUser => {
        User.findById(followId)
        .then( follows => {
            currentUser.addUser(follows)
        })
    })
    .catch(e => console.log(e)) 
})
 

Но таблица Follower_Followeds просто не будет обновляться.
Я также попытался пропустить реализацию Sequelize «многие ко многим», создав отдельную таблицу и добавив отношения вручную:

 const FollowerFollowed = sequelize.define('followerFollowed', {
  followedId: {
    type: Sequelize.INTEGER
  },

  followerId: {
    type: Sequelize.INTEGER
  }  
})

//define Users
  const User = sequelize.define('user', {
    firstName: {
      type: Sequelize.STRING
    },
    lastName: {
      type: Sequelize.STRING
    },
    email: {
      type: Sequelize.STRING
    },
    password: {
      type: Sequelize.STRING
    },
    activated: {
      type: Sequelize.BOOLEAN
    }
  })
 

И обработчик:

 app.post("/followhandler", function(req, res) {
    let userId = req.session.userId
    let followId = req.body.followId

    FollowerFollowed.create( {
        followerId: userId,
        followedId: followId
    })
    .then( rel => console.log(rel))
    .catch(e => console.log(e)) 
})
 

But I’m getting the following error in this case:

Ошибка типа: val.replace не является функцией в Object.SqlString.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/sql-string.js:61:15) в Object.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:978:22) в Object.InsertQuery (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:299:28 ) в QueryInterface.insert (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/query-interface.js:497:33) в . (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/instance.js:679:56) в tryCatcher (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/util.js:16:23) в Promise._settlePromiseFromHandler(/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:510:31) в Promise._settlePromise (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:567:18)в Promise._settlePromise0 (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:612:10) в Promise._settlePromises (/home/ piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:691:18) в Async._drainQueue (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:133:16) в Async._drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:143:10) в немедленном.Async.drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:17:14) при обратном вызове (timers.js:649:20) в tryOnImmediate (timers.js: 622:5) при промежуточном процессе [как _immediateCallback] (timers.js:594:5) Ошибка типа: val.replace не является функцией в Object.SqlString.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/sql-string.js:61:15) в Object.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:978:22) в Object.InsertQuery (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:299:28) в QueryInterface.insert (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/query-interface.js:497:33) в . (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/instance.js:679:56) в tryCatcher (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/util.js:16:23) в Promise._settlePromiseFromHandler(/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:510:31) в Promise._settlePromise (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:567:18)в Promise._settlePromise0 (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:612:10) в Promise._settlePromises (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js :691:18) в Async._drainQueue (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:133:16) в Async._drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js: 143:10) немедленно.Async.drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:17:14) в runCallback (timers.js:649:20) в tryOnImmediate (таймеры.js:622:5) в processImmediate [как _immediateCallback] (timers.js:594:5)

Ответ №1:

Когда вы создаете ассоциацию M: M, вы используете as: 'Follower' as: 'Followed' атрибуты и . Это влияет на то, как вы можете добавлять / устанавливать / удалять ассоциации между пользователями. Теперь вызывается метод добавления подписанного пользователя к другому пользователю addFollowed , и он будет использоваться точно так же, как вы это делали.

 User.findById(userId).then( currentUser => {
    User.findById(followId).then( follows => {
        currentUser.addFollowed(follows); // notice the difference here
    });
});
 

То же самое происходит, если вы хотите добавить подписчика к данному пользователю — тогда вы должны использовать addFollower метод.

Более того, в вашем втором решении вы допустили ошибку при создании ассоциирующей модели. В User модели вы определили ассоциации с помощью внешних ключей FollowerId и FollowedId , однако в FollowerFolloweds созданном вами определении followerId и followedId , поэтому эти два не совпадают друг с другом — вам необходимо поддерживать согласованность имен.

Редактировать

Согласно документации в belongsToMany отношении, as атрибут должен быть назван во множественном числе, поэтому в вашем случае вы должны назвать их as: 'Followers' и as: 'Followeds' (второе кажется немного странным). Sequelize выделяет эти значения самостоятельно, однако вы можете определить это самостоятельно, используя object as: { singular: 'Follower', plural: 'Followers' }

Псевдоним этой ассоциации. Если вы предоставляете строку, она должна быть множественной и будет выделена с помощью node.inflection . Если вы хотите самостоятельно управлять единственной версией, предоставьте объекту ключи множественного и единственного числа.