ATOM 103103 100 bytes, 9999 96 chars
{a=*/",";i=0;📏*∀{a.i🚪{📏(*/"("+*/"["+*/"{")!=📏(*/")"+*/"]"+*/"}")}:a.i+=","+a.(i+1);a-(i+1),i+=1};a}
Version 2
Saving a few characters by storing i+1 as a separate variable
{a=*/",";i=0;📏*∀{j=i+1;a.i🚪{📏(*/"("+*/"["+*/"{")!=📏(*/")"+*/"]"+*/"}")}:a.i+=","+a.j;a-j,i=j};a}
Usage
s="(1),{[2,3],4}";
s INTO {a=*/",";i=0;📏*∀{a.i🚪{📏(*/"("+*/"["+*/"{")!=📏(*/")"+*/"]"+*/"}")}:a.i+=","+a.(i+1);a-(i+1),i+=1};a}
Try it online
Explaination
It begins by splitting the original string by the comma into an array. It creates an iterator, and goes through each element in the created array. If the number of opening and closing symbols do not match, it will merge the current array element with the next one. If they do match, it will continue onwards. By the end of the iteration, all array elements should be correct, and it returns the final result.
Commented and organized code
{
a=*/","; # Split the input by the comma
i=0; # Declare an iterator
📏* FOREACH { # Repeat the following function based on the length of the string
a.i INTO {📏(*/"("+*/"["+*/"{")!=📏(*/")"+*/"]"+*/"}")}: # Check if the opening and closing characters match in the current item
a.i+=","+a.(i+1); # If there is not a match, add the next element to the current one
a-(i+1), # Remove the next element from the array and continue the loop
i+=1 # Else, increment the counter
};
a # Return the final array
}