mysqlsequelize.jskoa2

Sequelize with koa2 can't limit the record. How can I do?


async function selectCards ({
  status,
  teamId,
  userId,
  GMTTime,
  cardId,
  page,
  pageSize
}) {
  console.log(page, pageSize)
  const teamWhere = {}
  if (teamId) {
    teamWhere.id = teamId
  }
  const cardWhere = {}
  if (GMTTime) {
    cardWhere.startAt = {
      [Op.lt]: GMTTime
    }
  }
  if (cardId) {
    cardWhere.id = cardId
  }
  const userCardWhere = {
    userId
  }
  if (status) {
    userCardWhere.status = status
  }
  const result = await User.findOne({
    where: {
      id: userId
    },
    attributes: [],
    include: {
      model: Card,
      where: cardWhere,
      through: {
        where: userCardWhere
      },
      include: {
        model: Team,
        where: teamWhere,
        include: UserTeam
      }

      limit: pageSize // while it cause an error
    }
  })
  if (result == null) return { rows: [] }
  result.cards.map(card => {
    card.dataValues.status = card.user_card.status
    delete card.dataValues.user_card
    card.dataValues.team.dataValues.isAdmin = card.team.user_teams[0].isAdmin
    delete card.dataValues.team.dataValues.user_teams
    return card
  })
  return result
}

When i try to add limit as above An error has occurred

Only HasMany associations support include.separate Error: Only HasMany associations support include.separate

while one card will have many users and one user may have many cards it's a 'm:n' association

and when i try to use

order: [['startAt', 'desc']]

it also doesn't work

so i need to limit it by more code

  result.cards.sort((card1, card2) => (
    card2.startAt - card1.startAt
  ))
  const ret = result.cards.slice((page - 1) * pageSize, page * pageSize)
  return { rows: ret }

it's not a good choice to use more code because when data is too huge, it will need O(nlogn) to do can i have some solution just through sequelize?

by the way, it's the model association below

Team.hasMany(Card, {
  onDelete: 'CASCADE'
})
Card.hasOne(User, {
  onDelete: 'CASCADE',
  foreignKey: 'publishId'
})
Card.belongsTo(Team, {
  onDelete: 'CASCADE'
})

Card.belongsToMany(User, { through: UserCard })
User.belongsToMany(Card, { through: UserCard })
User.hasMany(UserCard)
UserCard.belongsTo(User)
Card.hasMany(UserCard)
UserCard.belongsTo(Card)

Solution

  • You can't use limit on parent records with many-to-many association included (especially with where in this include). This comes from SQL. If you join a parent and a child tables and then add limit that way you'll get first N mixed parent-child records and not first N parent records with all child records. Yes you can try a plain SQL query and you'll get a desired result but Sequelize cannot build such query for you. However you can try to get parent records with subqueries for filtering them by existence of some child records with certain conditions using sequelize.literal (and a SQL subquery like (EXISTS (SELECT 1 FROM CHILD_TABLE WHERE PARENT_ID=PARENT_TABLE.ID)). In that case you cannot get this child records in the same query but you can use limit properly. Afterwards you can get all child records separately by using a list of parent records' ids.