fredcrs fredcrs - 4 months ago 32
Node.js Question

Herarchy query using sequelize / nodejs

I am trying to load a hierarchy in my database. I have a column with parentId in my table so every row can have a parent. But I am having problems using recursion and promises.

function read (options) {
return serviceItemAttributeModel.findOne({
id: options.id,
id_organization: options.idOrganization
})
.then((attribute) => {
if (attribute) {
return loadChildren(attribute, attribute);
} else {
return attribute;
}
});
}

function loadChildren (root, attribute) {
return serviceItemAttributeModel.findAll({
where: {
id_parent: attribute.id
}
})
.then((attributes) => {
if (!attributes) {
return root;
} else {
attribute.serviceItemAttributes = [];
attributes.forEach(function (each) {
attribute.serviceItemAttributes.push(each);
return loadChildren(root, each);
});
}
});
}


So, I call read that calls loadChildren to recursively try to load all entities (by looking children of an entity) and I get an undefined value. Any ideas?

I am also getting an error on console: a promise was created in a handler but was not returned from it.

EDIT:

Came up if this solution after Nosyara help. thanks!:

function read (options) {
return serviceItemAttributeModel.findOne({
id: options.id,
id_organization: options.idOrganization
})
.then((attribute) => {
return new Promise(function (resolve, reject) {
attribute.queryCount = 1;
resolve(attribute);
});
})
.then((attribute) => loadChildren(attribute, attribute));
}

function loadChildren (root, attribute) {
return new Promise(function (resolve, reject) {
return serviceItemAttributeModel.findAll({
where: {
id_parent: attribute.id
}
})
.then((attributes) => {
attributes.length = attributes.length || 0;
root.queryCount = root.queryCount-1 + attributes.length;
if (root.queryCount === 0) {
resolve(root);
} else {
attribute.serviceItemAttributes = [];
attributes.forEach(function (each) {
attribute.serviceItemAttributes.push(each);
return loadChildren(root, each).then(() => {
resolve(root);
});
});
}
});
});
}

Answer

You messing up with async calls and returns. You can convert both function to async, and pass through result structure to be updated. Example:

function read(...) {
  return new Promise(function (accept, reject) {
    // You code goes here, but instead of return
    accept(resultFromAsyncFunction);
  }); 
}
// ...
read(...).then(function(resultData) { ... });

Here is example of Promise recursion.