Я использую Node.JS, Express, Sequelize и MySQL. У меня есть две таблицы, которые представляют узлы и ребра в древовидной структуре:
Таблица узлов
Таблица параметров
Узлы может иметь несколько вариантов. Параметры могут иметь 1 дочерний узел.
Я создал программу, которая рекурсивно генерирует объект JS, содержащий указанный узел и все дочерние узлы вплоть до листьев. Используя этот код:
/**
* Function to return a representation of the tree
* @param {number} aNode the id of the node to begin mapping from
* @returns {Object} object representing the database tree structure
*/
const dbMap = async (aNode) => {
const visited = [];
const queue = [];
const map = {};
try {
const node = await getNode(aNode);
const options = await getOptions(aNode);
if (node.article_id !== null) {
const articleTitle = await getNodeArticleTitle(node.article_id);
map.articleTitle = articleTitle.internal_name;
}
if (node){
map.node = node;
if (options){
map.options = options;
for (const option of options){
if (option.child_node_id){
queue.push(option.child_node_id);
}
}
}
}
map.children = [];
while (queue.length){
const node_to_find = queue.shift();
if (!visited.includes(node_to_find)){
map.children.push(await dbMap(node_to_find));
visited.push(node_to_find);
}
}
return map;
} catch (err) {
console.log(err);
return {error: err};
}
};
/**
* Get a node from its ID
* @param {number} node node's id to get
* @returns {Object} object representing a node
*/
const getNode = node => db.query('SELECT * FROM `nodes` WHERE `nodes`.`id` = ?',{
replacements: [node],
type: QueryTypes.SELECT,
plain: true,
raw:true
});
const getOptions = node => db.query('SELECT * FROM `options` WHERE `options`.`parent_node_id` = ?',{
replacements:[node],
type: QueryTypes.SELECT,
raw: true
});
Теперь я пытаюсь сделать то же самое, используя модели и ассоциации Sequelize, но могу вернуть только один уровень объекта дерева, используя этот код:
const node = db.define('node', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
primaryKey: true
},
title: {
type: DataTypes.STRING(120),
defaultValue: null
},
subtitle: {
type: DataTypes.STRING(500),
defaultValue: null
},
article_id: {
type: DataTypes.INTEGER,
defaultValue: null,
references: {
model: article,
key: 'id'
}
},
options_title: {
type: DataTypes.STRING(120),
defaultValue: null
},
options_type: {
type: DataTypes.ENUM,
values: ['grid', 'yes_no'],
defaultValue: null
}
});
node.hasMany(option, {
as: 'options',
foreignKey: 'parent_node_id'
});
node.hasOne(article, {
as: 'article',
foreignKey: 'id'
});
const option = db.define('option', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
primaryKey: true
},
title: {
type: DataTypes.STRING(120),
allowNull: false,
unique: true
},
sub_title: {
type: DataTypes.STRING(500),
defaultValue: null
},
image: {
type: DataTypes.STRING(120),
defaultValue: null
},
position: {
type: DataTypes.INTEGER,
allowNull: false
},
parent_node_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: node,
key: 'id'
}
},
child_node_id: {
type: DataTypes.INTEGER,
references: {
model: node,
key: 'id'
}
}
});
option.associate = (models) => {
option.belongsTo(models.node, {
foreignKey: 'child_node_id',
as: 'childNode'
});
};
node.findOne({
where: {
id: 1
},
include: [{all: true, nested: true}]
}).then((response) => response.toJSON()).then((result) => {
console.log(result);
});
который возвращает:
{
id: 1,
title: 'How can we help you today?',
subtitle: '',
article_id: null,
options_title: null,
options_type: 'grid',
options: [
{
id: 1,
title: '',
sub_title: null,
image: null,
position: 1,
parent_node_id: 1,
child_node_id: 2
},
{
id: 2,
title: '+',
sub_title: null,
image: null,
position: 2,
parent_node_id: 1,
child_node_id: 3
},
{
id: 3,
title: 'Block',
sub_title: null,
image: null,
position: 3,
parent_node_id: 1,
child_node_id: 4
},
{
id: 4,
title: 'Orders / Returns',
sub_title: null,
image: null,
position: 4,
parent_node_id: 1,
child_node_id: 5
},
{
id: 5,
title: 'App',
sub_title: null,
image: null,
position: 5,
parent_node_id: 1,
child_node_id: 6
},
{
id: 6,
title: 'Suggestions',
sub_title: null,
image: null,
position: 6,
parent_node_id: 1,
child_node_id: 7
}
],
article: null
}
Как мне определить модели и ассоциации, а затем запросить их, чтобы вернуть объект на листья?