Sequelize 中如何实现树形结构查询

在前端开发中,树形结构数据查询是常见的需求。Sequelize 是一款 Node.js 的 ORM(对象关系映射)框架,提供了非常便捷的数据库操作方式。本文将介绍在 Sequelize 中如何查询树形结构数据。

关系型数据库中的树形结构

在关系型数据库中,树形结构数据通常以两种方式存储:

  1. 存储父节点 ID。表中会有一个字段存储当前节点的父节点 ID,如果该节点没有父节点,则父节点 ID 为 NULL。
  2. 存储子节点列表。表中会有一个字段存储当前节点的子节点列表,通常以 JSON 或数组的格式存储。

以下以第一种方式为例,介绍在 Sequelize 中如何实现树形结构查询。

准备工作

在开始之前,需要先安装 Sequelize 和 mysql2。可以使用 npm 安装:

数据库模型

假设有一个表 categories 存储商品分类信息,表结构如下:

CREATE TABLE `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `parent_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

其中,parent_id 表示当前节点的父节点 ID,如果该节点没有父节点,则 parent_id 为 NULL。

在 Sequelize 中,可以定义一个 Category 模型来操作该表:

const { Sequelize, Model } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'mysql',
});

class Category extends Model {}
Category.init(
  {
    name: Sequelize.STRING,
    parentId: Sequelize.INTEGER,
  },
  { sequelize, modelName: 'category' }
);

module.exports = Category;

查询树形结构数据

首先,可以通过以下方法查询顶级节点:

const Category = require('./models/category');

const rootCategories = await Category.findAll({
  where: {
    parentId: null,
  },
});

然后,可以递归查询子节点。以下是基础版的递归查询方法:

async function loadChildren(categories) {
  for (const category of categories) {
    const children = await Category.findAll({
      where: {
        parentId: category.id,
      },
    });

    if (children.length > 0) {
      await loadChildren(children);
    }

    category.children = children;
  }
}

以上方法中,category.children 存储每个节点的子节点列表。

但是,以上方法会导致 N + 1 查询问题,影响性能。为了解决这个问题,可以使用 Sequelize 提供的 bulkCreatebulkUpdate 方法进行批量操作。

以下是优化版的递归查询方法:

async function loadChildren(categories) {
  const map = new Map();

  for (const category of categories) {
    map.set(category.id, category);
  }

  const children = await Category.findAll({
    where: {
      parentId: {
        [Sequelize.Op.in]: Array.from(map.keys()),
      },
    },
  });

  for (const child of children) {
    const parent = map.get(child.parentId);

    if (!parent.children) {
      parent.children = [];
    }

    parent.children.push(child);
  }

  if (children.length > 0) {
    await loadChildren(children);
  }
}

以上方法中,loadChildren 通过 Map 存储节点对象,以 parentId 为条件查询子节点,并将子节点添加到父节点的 children 属性中。这样,就实现了一次查询获取所有数据的目的。此时,可以通过以下方法查询所有数据:

const rootCategories = await Category.findAll({
  where: {
    parentId: null,
  },
});

await loadChildren(rootCategories);

总结

本文介绍了在 Sequelize 中如何查询树形结构数据。通过递归查询和批量操作,可以优化查询性能,提高网页响应速度。对于需要查询树形结构数据的应用场景,可以根据实际需求灵活运用本文介绍的技术方案。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b09996add4f0e0ff9f3e74