递归包括Sequelize?
Recursive include Sequelize?
我的类别可以有子类别
当我执行 findAll 时,我想包括所有嵌套的,但我不知道深度。
var includeCondition = {
include: [
{
model: models.categories,
as:'subcategory', nested: true
}]
};
models.categories.findAll(includeCondition)
.then(function (categories) {
resolve(categories);
})
.catch(function (err) {
reject(err);
})
});
结果只给我带来了一层嵌套包含。
[
{
dataValues:{
},
subcategory:{
model:{
dataValues:{
}
// no subcategory here
}
}
}
]
我能否以某种方式使 sequalize 包括那些嵌套的子类别?
如果找到解决方案很少
第一个更复杂,但会提供更好的性能:
这是关于在 MySQL 中实现分层数据结构
我喜欢这里的指南
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
名为嵌套集模型的模型。
我自己实际实现的第二个解决方案是递归扩展,这个使用了很多 mysql 请求,我相信可以改进,但它很快并且效果很好。关键是要像这样使用每个类别函数
var expandSubcategories = function (category) {
return new promise(function (resolve, reject) {
category.getSubcategories().then(function (subcategories) {
//if has subcategories expand recursively inner subcategories
if (subcategories && subcategories.length > 0) {
var expandPromises = [];
_.each(subcategories, function (subcategory) {
expandPromises.push(expandSubcategories(subcategory));
});
promise.all(expandPromises).then(function (expandedCategories) {
category.subcategories = [];
_.each(expandedCategories, function (expandedCategory) {
category.subcategories.push(expandedCategory);
}, this);
//return self with expanded inner
resolve(category);
});
} else {
//if has no subcategories return self
resolve(category);
}
});
});
};
所以它遍历类别并递归地扩展它们。
也许这也会对某人有所帮助。
有一个处理它的节点模块:sequelize-hierarchy
它将列 parentId 和 hierarchyLevel 添加到您的 table。
例如,这就是我在树中对员工技能进行排序的方法。
技能可以是“Macro”->“Excel”->“Office” -> “计算机”
database.js:
const Sequelize = require('sequelize');
require('sequelize-hierarchy')(Sequelize);
const sequelize = new Sequelize("Whosebug", null, null, {
dialect: "sqlite",
storage: "database.db"
});
sequelize.sync().then(() => {console.log("Database ready");});
module.exports = sequelize;
skill.js:
module.exports = (sequelize, DataTypes) => {
const Skill = sequelize.define("skill", {
name: DataTypes.STRING,
});
Skill.isHierarchy();
return Skill;
};
然后在你的控制器中:
Skill.findAll().then(skills => {
res.send(skills); // Return a list
});
Skill.findAll({ hierarchy: true }).then(skills => {
res.send(skills); // Return a tree
});
假设您有 5 个不同的模型 A、B、C、D、E,并且 A 与 B 关联,B 与 C 关联,依此类推。
因此,在为 A 获取数据时,您可以使用
获取所有嵌套的子类别层次结构
include: [{ all: true, nested: true }]
示例:
A.findAll(where:{// add conditions}, { include: [{ all: true, nested: true }]});
这是 ihoryam 针对 ES6 改编的答案,使用 async/await
、箭头函数 () =>
和 Sequelize ORM 来获取数据,而不是使用 Lodash。
const getSubCategoriesRecursive = async (category) => {
let subCategories = await models.category.findAll({
where: {
parentId: category.id
},
raw : true
});
if (subCategories.length > 0) {
const promises = [];
subCategories.forEach(category => {
promises.push(getSubCategoriesRecursive(category));
});
category['subCategories'] = await Promise.all(promises);
}
else category['subCategories'] = [];
return category;
};
异步函数返回承诺,你不需要精确return new promise(...)
Sequelize 目前不支持常见的 table 表达式和递归 CTE。添加将 CTE 包含到 find* 方法系列中的功能将允许 find* 执行递归查询。
这里是link的例子。
我的类别可以有子类别
当我执行 findAll 时,我想包括所有嵌套的,但我不知道深度。
var includeCondition = {
include: [
{
model: models.categories,
as:'subcategory', nested: true
}]
};
models.categories.findAll(includeCondition)
.then(function (categories) {
resolve(categories);
})
.catch(function (err) {
reject(err);
})
});
结果只给我带来了一层嵌套包含。
[
{
dataValues:{
},
subcategory:{
model:{
dataValues:{
}
// no subcategory here
}
}
}
]
我能否以某种方式使 sequalize 包括那些嵌套的子类别?
如果找到解决方案很少 第一个更复杂,但会提供更好的性能:
这是关于在 MySQL 中实现分层数据结构 我喜欢这里的指南
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
名为嵌套集模型的模型。
我自己实际实现的第二个解决方案是递归扩展,这个使用了很多 mysql 请求,我相信可以改进,但它很快并且效果很好。关键是要像这样使用每个类别函数
var expandSubcategories = function (category) {
return new promise(function (resolve, reject) {
category.getSubcategories().then(function (subcategories) {
//if has subcategories expand recursively inner subcategories
if (subcategories && subcategories.length > 0) {
var expandPromises = [];
_.each(subcategories, function (subcategory) {
expandPromises.push(expandSubcategories(subcategory));
});
promise.all(expandPromises).then(function (expandedCategories) {
category.subcategories = [];
_.each(expandedCategories, function (expandedCategory) {
category.subcategories.push(expandedCategory);
}, this);
//return self with expanded inner
resolve(category);
});
} else {
//if has no subcategories return self
resolve(category);
}
});
});
};
所以它遍历类别并递归地扩展它们。
也许这也会对某人有所帮助。
有一个处理它的节点模块:sequelize-hierarchy
它将列 parentId 和 hierarchyLevel 添加到您的 table。
例如,这就是我在树中对员工技能进行排序的方法。
技能可以是“Macro”->“Excel”->“Office” -> “计算机”
database.js:
const Sequelize = require('sequelize');
require('sequelize-hierarchy')(Sequelize);
const sequelize = new Sequelize("Whosebug", null, null, {
dialect: "sqlite",
storage: "database.db"
});
sequelize.sync().then(() => {console.log("Database ready");});
module.exports = sequelize;
skill.js:
module.exports = (sequelize, DataTypes) => {
const Skill = sequelize.define("skill", {
name: DataTypes.STRING,
});
Skill.isHierarchy();
return Skill;
};
然后在你的控制器中:
Skill.findAll().then(skills => {
res.send(skills); // Return a list
});
Skill.findAll({ hierarchy: true }).then(skills => {
res.send(skills); // Return a tree
});
假设您有 5 个不同的模型 A、B、C、D、E,并且 A 与 B 关联,B 与 C 关联,依此类推。 因此,在为 A 获取数据时,您可以使用
获取所有嵌套的子类别层次结构include: [{ all: true, nested: true }]
示例:
A.findAll(where:{// add conditions}, { include: [{ all: true, nested: true }]});
这是 ihoryam 针对 ES6 改编的答案,使用 async/await
、箭头函数 () =>
和 Sequelize ORM 来获取数据,而不是使用 Lodash。
const getSubCategoriesRecursive = async (category) => {
let subCategories = await models.category.findAll({
where: {
parentId: category.id
},
raw : true
});
if (subCategories.length > 0) {
const promises = [];
subCategories.forEach(category => {
promises.push(getSubCategoriesRecursive(category));
});
category['subCategories'] = await Promise.all(promises);
}
else category['subCategories'] = [];
return category;
};
异步函数返回承诺,你不需要精确return new promise(...)
Sequelize 目前不支持常见的 table 表达式和递归 CTE。添加将 CTE 包含到 find* 方法系列中的功能将允许 find* 执行递归查询。
这里是link的例子。