我可以在 Sequelize.js 中的单个查询中获取 ID 为 1 的类别和该类别的所有子类别吗?

Posted

技术标签:

【中文标题】我可以在 Sequelize.js 中的单个查询中获取 ID 为 1 的类别和该类别的所有子类别吗?【英文标题】:Can I get Category with id 1 and all Subcategories of that Category in a single query in Sequelize.js? 【发布时间】:2020-10-21 14:25:52 【问题描述】:

我有以下数据库表:

Table: Categories
Columns: id, name, parent_id

以及以下记录:

1 / Category1 / 0
2 / Category2 / 0
3 / Subcategory1 / 1
4 / Subcategory2 / 1

所以我有 2 个类别 - Category1 和 Category2 以及 Category1 的 2 个子类别 - Subcategory1 和 Subcategory2。

如果 parent_id 字段为 0,则表示该记录是一个类别,如果它不为 0 并且具有另一个类别的 id,则它是该类别的子类别。

现在我得到所有这样的类别:

Category.findAll(
    where: 
        'parent_id': 0
    
)
.then(result => 
    console.log(result)
)
.catch(error => 
    console.log(error)
)

但现在我还想以某种方式将类别的子类别包含为对象属性。现在我得到了这个:

[
    
      "id": 1,
      "name": "Category1",
      "parent_id": 0
    
]

我想得到这样的东西:

[
    
      "id": 1,
      "name": "Category1",
      "parent_id": 0,
      "subcategories": [
          
              "id": 3,
              "name": "Subcategory1",
              "parent_id": 1,
          ,
          
              "id": 4,
              "name": "Subcategory2",
              "parent_id": 1,
          
      ]
    
]

它类似于预加载,但它就像模型预加载本身。我怎样才能在尽可能少的查询中做到这一点?

【问题讨论】:

【参考方案1】:

您需要使用sequelize.define() 创建一个支持您的表格的Model,在本例中为“类别”

// first define your model, you don't have to define the `id` or `parent_id` as they will be created automatically
const Categories = sequelize.define('categories', 
  name: 
    type: DataTypes.STRING(255),
  ,
,

  // use underscores in generated column names
  underscored: true,
);

现在为模型创建 parent-

// relate a category to its parent=
Categories.belongsTo(Categories, 
  as: 'parent', 
  foreignKey: 'parent_id', 
  targetKey: 'id',
);

// relate parent to child categories
Categories.hasMany(Categories, 
  as: 'subcategories',
  foreignKey: 'parent_id',
);

现在您可以使用include 选项传入Model 并指定as 参数以加载正确的关系。传入required: false 以使用左连接,以便在没有子类别的情况下返回结果。

// ... your code

// now you can include the subcategories and 
// pass in the parent_id into the where clause
const category = await Categories.findOne(
  include: 
    model: Categories,
    as: 'subcategories',
    required: false,
  ,
  where: 
    parent_id: 0,
  ,
);

// if you know the ID you want is 1...
const category = await Categories.findByPk(1, 
  include: 
    model: Categories,
    as: 'subcategories',
    required: false,
  ,
);

在相反的方向,从孩子到父母,或者在这种情况下两者都......

// To get a category and its parent and children...
const categoryWithParentAndSubcategories = await Categories.findByPk(123, 
  include: [
    
      model: Categories,
      as: 'parent',
      required: false,
    ,
    
      model: Categories,
      as: 'subcategories',
      required: false,
    ,
  ],
);

// you can keep going for multiple levels if you want

// To get a category and its grandparent, parent and children...
const categoryWithParentAndSubcategories = await Categories.findByPk(123, 
  include: [
    
      model: Categories,
      as: 'parent',
      required: false,
      include: 
        model: Categories,
        as: 'parent',
        required: false,
      ,
    ,
    
      model: Categories,
      as: 'subcategories',
      required: false,
    ,
  ],
);

【讨论】:

以上是关于我可以在 Sequelize.js 中的单个查询中获取 ID 为 1 的类别和该类别的所有子类别吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Sequelize.js 和 PostgreSQL 在关联模型上查询 JSONB 字段

Sequelize.js - 连接子句中的子选择

Sequelize(或清除 SQL)查询以选择包含 JSON 字段中的值的行?

Sequelize将日期从UTC转换为本地

Sequelize JS 自定义查询与子选择

sequelize.js 中的字母数字 ID