Access a nested array of objects in nodejs, mysql and json

Issue

I have these tables:

CREATE TABLE Progress_Category (
    categoryId int(4) AUTO_INCREMENT NOT NULL,
    name varchar(150) NOT NULL,
    PRIMARY KEY (categoryId)
);
CREATE TABLE Progress_Skill (
    skillId int(4) AUTO_INCREMENT NOT NULL,
    name varchar(150) NOT NULL,
    currentProgress int NOT NULL,
    `25` varchar(300) NOT NULL,
    `50` varchar(300) NOT NULL,
    `75` varchar(300) NOT NULL,
    `100` varchar(300) NOT NULL,
    categoryId int(4) NOT NULL,
    PRIMARY KEY (skillId),
    CONSTRAINT Constr_Progress_Skill_Skill_fk FOREIGN KEY Skill_fk (categoryId) REFERENCES Progress_Category(categoryId) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE Progress_Message (
    messageId int(4) AUTO_INCREMENT NOT NULL,
    message varchar(500) NOT NULL,
    messageDate DATE NOT NULL,
    skillId int(4) NOT NULL,
    PRIMARY KEY (messageId),
    CONSTRAINT Constr_Progress_Message_Message_fk FOREIGN KEY Message_fk (skillId) REFERENCES Progress_Skill(skillId) ON DELETE CASCADE ON UPDATE CASCADE
);

I have this query to retrieve all the data in a table:

SELECT *
    FROM Progress_Category AS pcat
        LEFT JOIN Progress_Skill AS ps
            ON pcat.categoryId = ps.catParentId
        LEFT JOIN Progress_Message AS pm
            ON ps.skillId = pm.skillParentId

For each skill of a category a new row of category will be created, with the respected skill. For each message of a skill a new row with the category and the skill will be created, with the respected message.

Query result:

+------------+-----------+---------+-----------+-----------------+------+-------+--------+-------+-------------+-----------+-------------------------+-------------+---------------+
| categoryId | catname   | skillId | skillname | currentProgress | 25   | 50    | 75     | 100   | catParentId | messageId | message                 | messageDate | skillParentId |
+------------+-----------+---------+-----------+-----------------+------+-------+--------+-------+-------------+-----------+-------------------------+-------------+---------------+
|          1 | Languages |       1 | Spanish   |             100 | Read | Write | Listen | Speak |           1 |         1 | Native language         | 2022-08-27  |             1 |
|          1 | Languages |       2 | English   |              85 | Read | Write | Listen | Speak |           1 |         2 | Learning since 2016     | 2022-08-27  |             2 |
|          1 | Languages |       2 | English   |              85 | Read | Write | Listen | Speak |           1 |         3 | Can speak almost fluent | 2022-08-27  |             2 |
|          2 | Projects  |    NULL | NULL      |            NULL | NULL | NULL  | NULL   | NULL  |        NULL |      NULL | NULL                    | NULL        |          NULL |
|          3 | Ideas     |    NULL | NULL      |            NULL | NULL | NULL  | NULL   | NULL  |        NULL |      NULL | NULL                    | NULL        |          NULL |
+------------+-----------+---------+-----------+-----------------+------+-------+--------+-------+-------------+-----------+-------------------------+-------------+---------------+
5 rows in set (0.001 sec)

In nodejs I use that query and the following code:

connection.query(myquery, function(err, results, fields) {
    if (err) {
        console.log('----> Error with MySQL query in /api/showProgress: ' + err.message);
    }
    else{
        console.log('Query successful, results are being displayed.');
            
        var categories = [];
        for (let category in results) {
            if(categories.length > 0){
                for(let key in categories){
                    if(results[category].categoryId !== categories[key].Category.Id){
                        console.log("Category Id: " + results[category].categoryId + " Id already in the array: " + categories[key].Category.Id);
                        categories.push({
                            "Category" : [{
                                "Id" : results[category].categoryId,
                                "Name" : results[category].catname
                            }]
                        });
                    }
                }
            }
        }
        else{
            categories.push({
                "Category" : [{
                    "Id" : results[category].categoryId,
                    "Name" : results[category].catname
                }]
            })
        }
    }
    response.send({"My progress" : categories});
});

The result I get:

Query successful, results are being displayed.
Category Id: 1 Id already in the array: undefined
Category Id: 1 Id already in the array: undefined
Category Id: 1 Id already in the array: undefined
Category Id: 2 Id already in the array: undefined
Category Id: 2 Id already in the array: undefined
Category Id: 2 Id already in the array: undefined
Category Id: 2 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined
Category Id: 3 Id already in the array: undefined

So the problem is categories[key].Category.Id. I don’t know how to access the property Id that belong to Category that is in the array.

The final idea is use that if so only one category is shown with an array of skills instead of a category, skill, same category, other skill:

Current:

{"My progress":[
    {
        "Category":[{
            "Id":1,
            "Name":"Languages",
            "Skill":"asd"
        }]
    },
    {
        "Category":[{
            "Id":1,
            "Name":"Languages",
            "Skill":"fgh"
        }]
    },
    {
        "Category":[{
            "Id":1,
            "Name":"Languages",
            "Skill":"ijk"
        }]
    },
]}

Expected:

{"My progress":[
    {
        "Category":[
            {
                "Id":1,
                "Name":"Languages",
                "Skills":[{
                    "Name":"asd",
                    "Name":"fgh",
                    "Name":"ijk"
                }]
            },
            {
                "Id":2,
                "Name":"Projects",
                "Skills":[{
                    "Name":"123",
                    "Name":"456",
                    "Name":"789"
                }]
            }
        ]
    }
]}

Solution

Got the expected result, changing almost everything:

{"My skills":[
    {
        "categoryId":1,
        "CategoryName":"Web development",
        "Subcategories":[
            {
                "parentId":1,
                "subcategoryId":1,
                "SubcategoryName":"Frontend",
                "Skills":[
                    "Sass",
                    "Css",
                    "Bootstrap",
                    "Figma"
                ]
            },
            {
                "parentId":1,
                "subcategoryId":2,
                "SubcategoryName":"Backend",
                "Skills":[
                    "Nodejs",
                    "Express",
                    "MySQL",
                    "PHP"
                ]
            }
        ]
    },
    {
        "categoryId":2,
        "CategoryName":"Cybersecurity",
        "Subcategories":[
            {
                "parentId":2,
                "subcategoryId":3,
                "SubcategoryName":"Red team",
                "Skills":[
                    "curl",
                    "Sherlock",
                    "Wappalyzer",
                    "Burpsuite"
                ]
            },
            {
                "parentId":2,
                "subcategoryId":4,
                "SubcategoryName":"Blue team",
                "Skills":[
                    "Cloudfare"
                ]
            }
        ]
    }
]}

Nodejs code:

connection.query(myquery, function(err, results, fields) {
    if (err) {
        console.log('----> Error with MySQL query in /api/showSkills: ' + err.message);
    }
    else{
        console.log('Query successful, results are being displayed.');
        
        var mylist = [];
        var subcat = [];
        var lastPushedId = 0;
        for (let key in results){
            if(lastPushedId !== results[key].categoryId){
                for (let otherkey in results){
                    if(results[otherkey].subcatParentId === results[key].categoryId){
                        subcat.push({
                            'parentId': results[otherkey].subcatParentId,
                            'subcategoryId': results[otherkey].subcategoryId,
                            'SubcategoryName': results[otherkey].subcatname,
                            'Skills': results[otherkey].skills.split(',')
                        });
                    }
                }
                mylist.push({
                    'categoryId': results[key].categoryId,
                    'CategoryName': results[key].catname,
                    'Subcategories': subcat
                });
                subcat = [];
                lastPushedId = results[key].categoryId;
            }
        }
            response.send({"My skills" : mylist});
    }
});

Answered By – LautaroColella

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published