【问题标题】:Is it possible to do a multi tenancy with Graphql and Sequelize?是否可以使用 Graphql 和 Sequelize 进行多租户?
【发布时间】:2026-02-08 07:05:02
【问题描述】:

强调文本我有一个关于 GraphQl 和多租户的相当棘手的问题。

假设有 3 个表,OWNERHOUSETENANTS。我将在 Sequelize 和 GraphQl 伪代码中描述它们:

Owner 表(有多个房屋和多个租户)

const OWNER = sequelize.define('owner', {
  ownerId: type: Sequelize.INTEGER,
  name: type: Sequelize.STRING
}

OWNER.associate = models => {
  models.owner.hasMany(models.house, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
  models.owner.hasMany(models.tenant, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
}

房屋表(属于所有者,有多个租户)

const HOUSE = sequelize.define('house', {
  houseId: type: Sequelize.INTEGER,
  ownerId: type: Sequelize.INTEGER,
  name: type: Sequelize.STRING
}

HOUSE.associate = models => {
  models.house.belongsTo(models.owner, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
  models.house.hasMany(models.tenant, {foreignKey: {name: 'houseId', field: 'houseId'}})
}

租户表(属于业主和房屋)

const TENANT = sequelize.define('tenant', {
  tenantId: type: Sequelize.INTEGER,
  ownerId: type: Sequelize.INTEGER,
  houseId: type: Sequelize.INTEGER,
  name: type: Sequelize.STRING
}

TENANT.associate = models => {
  models.tenant.belongsTo(models.owner, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
  models.tenant.belongsTo(models.house, {foreignKey: {name: 'houseId', field: 'houseId'}})
}

拥有者 graphql 对象

const OwnerType = new GraphQLObjectType({
  name: 'Owner',
  fields: () => ({
    ownerId: { type: GraphQLInt },
    name: { type: GraphQLString },
    houses: {
      type: GraphQLList(HouseType),
      resolve(owner) {
        return owner.getHouse()
      }
    },
    houseById: {
      type: HouseType,
      args: <args is not defined>
      resolve(owner) {
        return <???>
      }
    },
  })
})

以下是一些简单的 GraphQL 查询:

ownerById = {
  type: OwnerType,
  args: {
    ownerId: { type: GraphQLInt },
  },
  resolve(parents, args){
    return models.owner.findOne({ where: args })
  }
}

houses = {
  type: GraphQLList(HouseType),
  resolve(parents, args){
    return models.house.findAll()
  }
}

houseById = {
  type: HouseType,
  args: {
    houseId: { type: GraphQLInt },
  },
  resolve(parents, args){
    return models.house.findOne({ where: args })
  }
}

tenants = {
  type: GraphQLList(TenantType),
  resolve(parents, args){
    return models.tenant.findAll()
  }
}

这些客户端查询有效:

{
  ownerById(ownerId: 1) {
    ownerId
    name
    house {
      houseId
      name
    }
  }
}

{
  houseById(houseId: 2) {
    houseId
    name
    tenant {
      tenantId
      name
    }
  }
}

我需要让多租户工作是这样的:

{
  ownerById(ownerId: 1) {
    ownerId
    name
    houseById(houseId: 2) {
      houseId
      name
      tenant {
        tenantId
        name
      }
    }
  }
}

有没有办法存档这个或者超出 GraphQl 可以做什么的范围?

如果是,graphql 对象houseById 查询是什么样的?

提前致谢。

【问题讨论】:

  • 目前尚不清楚您对houseById(ownerId: 2) 的要求是什么,至少在您描述的数据模型的上下文中是这样。 Owner 和 House 之间存在一对多的关系。通过 id (ownerById(ownerId: 1)) 获取 Owner 节点后,该节点的任何字段都将与该特定节点相关。因此,我不确定您通过允许消费者为其中一个字段指定不同的ownerId 来尝试做什么。你能澄清你的问题吗?
  • 你是在问如何构造一个包含多个查询的请求吗?或者您是在问如何通过一个或多个任意参数过滤“嵌套”(即非根)字段?还是完全不同的东西?
  • 对不起@DanielRearden ownerId 应该说houseId。我的坏...

标签: graphql sequelize.js multi-tenant


【解决方案1】:

除非我遗漏了什么,否则houseById 的解析器似乎与同一类型的 houses 字段的解析器没有太大区别。

houseById: {
  type: HouseType,
  args: {
    houseId: { type: GraphQLInt },
  },
  async resolve(owner, { houseId }) {
    const houses = await owner.getHouses({ where: { id: houseId } })
    return houses[0]
  }
},

对于HasMany 关联,目标模型的getter 解析为实例数组。所以我们需要先获取该数组,然后只返回其中的第一项,因为我们的字段表示单个对象而不是列表。如果不想使用 async/await,也可以这样做:

return owner.getHouses({ where: { id: houseId } })
  .then(houses => houses[0])

还值得一提的是,这种模式的模式违反了约定。与其拥有houses 字段、houseById 字段、houseBySomeOtherArg 字段等,不如考虑公开一个带有一个或多个参数的houses 字段,例如idname 或您的任何过滤条件想提供。然后,您的字段可以根据传入的任何参数过滤房屋,或者如果没有提供过滤器参数,则返回所有结果。

【讨论】:

  • 嗨丹尼尔,你是对的。我只是忘记了resolve() 函数中的args 参数。最后我的现场道具看起来有点不同。我没有传递 owner 并使用 getHouses() 函数,而是导入了 Sequelize models 并像这样使用了 findOne() 函数:resolve(owner, args) { return models.house.findOne({ where: args }) }