0

My php generates two JSON arrays like:

[{"category":183,"private_review_ids":[63,59,62]},
{"category":363,"private_review_ids":[331]}, 
{"category":371,"private_review_ids":[341]},
{"category":379,"private_review_ids":[350]}]
[{"category":363,"public_review_ids":[331]},
{"category":373,"public_review_ids":[343]},
{"category":384,"public_review_ids":[356]},
{"category":183,"public_review_ids":[347]}]

How could I merge these arrays so they are just one array of the form below. It is not simply merging the arrays - it is the possible tranferring of the value from one key (public_review_ids) to another key (private_review_ids) within the JSON Object. Here's the form I want the JSON Array:

[{"category":183,"private_review_ids":[63,59,62],"public_review_ids":[347] },
{"category":363,"private_review_ids":[331],"public_review_ids":[]}, 
{"category":371,"private_review_ids":[341],"public_review_ids":[]},
{"category":379,"private_review_ids":[350]},"public_review_ids":[]},
{"category":373,"private_review_ids":[],"public_review_ids":[343]},
{"category":384,"private_review_ids":[],"public_review_ids":[356]}]

As you can see, if the value is in both private_review_ids and public_review_ids, it should appear in just the private_review_ids key.

I tried using array_unique and array_merge but I was having no success, really.

Here's my code:

<?php
require('myfile.php');

    //here is the user_id, which is the corresponding user_id for username +5555555

$user_id = "21";
//Select all related info in the review_shared table 
//where the contact_id column is equal to $user_id.

//a value in the contact_id column means a review is shared with a person, $user_name,
//who owns that number, $user_id
$sql = "SELECT * FROM review_shared WHERE contact_id = ?";
$stmt2 = $con->prepare($sql) or die(mysqli_error($con));
$stmt2->bind_param('i', $user_id) or die ("MySQLi-stmt binding failed ".$stmt2->error);
$stmt2->execute() or die ("MySQLi-stmt execute failed ".$stmt2->error);
$result2 = $stmt2->get_result();

//fetch all rows associated with the respective contact_id value
//in review_shared table
while ($row = $result2->fetch_assoc()) {

    //get the corresponding cat_id in the row
    $cat_id = $row["cat_id"];

    //get the corresponding review_id in the row
    $review_id = $row["review_id"];
    //make an array called $results
    $results[$row['cat_id']][] = $review_id; 

}

$jsonData = array_map(function($catId) use ($results) {
    return [
        'category' => $catId,
        'private_review_ids' => $results[$catId],
        ];
}, array_keys($results));
echo json_encode($jsonData);


    //**********************

//select all rows where public_or_private column = 2
//in review table
$sql2 = "SELECT * FROM review WHERE public_or_private = 2";
$result2 = mysqli_query($con,$sql2);

    //fetch all associated rows where public_or_private column = 2
    while ($row = $result2->fetch_assoc()) {

    //get the corresponding review_id in the row
    $review2_id = $row["review_id"];

    //get the corresponding cat_id in the row
    $cat2_id = $row["cat_id"];

    //make an array called $results
    $results2[$row['cat_id']][] = $review2_id;              

    }

    $jsonData2 = array_map(function($cat2Id) use ($results2) {
    return [
        'category' => $cat2Id,
        'public_review_ids' => $results2[$cat2Id],
        ];
}, array_keys($results2));
echo json_encode($jsonData2);


?>
CHarris
  • 2,693
  • 8
  • 45
  • 71

1 Answers1

1

If you refactor your code, you can remove the need for iterating over the data 4 times (twice each) by immediately appending the query results into your desired data structure.

If you execute your public and private review queries, such that their results are in variables $publicReviews and $privateReviews then:

<?php

// Public and private review query results
$publicReviews = $stmt1->get_result();
$privateReviews = $stmt2->get_result();

// Prepare combined reviews array
$reviews = [];

// Iterate through private review results and append to combined reviews
while (($row = $privateReviews->fetch_assoc())) {
    $category_id = $row['cat_id'];
    $review_id = $row['review_id'];

    $reviews[$category_id]['category'] = $category_id;
    $reviews[$category_id]['private_review_ids'][] = $review_id;
    $reviews[$category_id]['public_review_ids'] = [];
}

// Iterate through public review results and append to combined reviews
while (($row = $publicReviews->fetch_assoc())) {
    $category_id = $row['cat_id'];
    $review_id = $row['review_id'];

    $reviews[$category_id]['category'] = $category_id;

    // Create empty private reviews array, where it doesn't exist
    if (! isset($reviews[$category_id]['private_review_ids'])) {
        $reviews[$category_id]['private_review_ids'] = [];
    }

    // Add review id to public reviews where it doesn't exist in private reviews
    if (! in_array($review_id, $reviews[$category_id]['private_review_ids'])) {
        $reviews[$category_id]['public_review_ids'][] = $review_id;
    }
}

echo json_encode(array_values($reviews));
fubar
  • 16,918
  • 4
  • 37
  • 43
  • I am getting `Parse error: syntax error, unexpected '?' in /var/www/html/CategorySearch.php on line 43` which is the line `$reviews[$cat_id]['public_review_ids'] = $reviews[$cat_id]['public_review_ids'] ?? [];` When I remove the extra `?` I get `Parse error: syntax error, unexpected ';' in /var/www/html/CategorySearch.php on line 43` – CHarris Apr 03 '18 at 22:24
  • Are you not using PHP7+? – fubar Apr 03 '18 at 22:39
  • It looks like I have PHP Version 5.5.9-1ubuntu4.21. Should I update? Not that old though, Feb 2017. In any case I am having an issue getting the result in variable $publicReviews, let me look more into it... – CHarris Apr 03 '18 at 22:46
  • 1
    PHP 5.5 was EOL in July 2016, so yes, you may want to consider upgrading. As for the variables, `$publicReviews`, I merely renamed them in my answer for clarity. You just need to get query results in the correct order for the `while` loops to work. I'll update my answer to make it work without the null coalese operator. – fubar Apr 03 '18 at 22:49
  • Tx, the JSON should be an array, yes? Right now the output is like: `{"383":{"private_review_ids":[353],"public_review_ids":[]},"203":{"private_review_ids":[149],"public_review_ids":[]},"239":{"private_review_ids":[201],"public_review_ids":[]}}` I want it to be like: `[{"category":"383", "private_review_ids":[353],"public_review_ids":[]},"category":"203","private_review_ids":[149],"public_review_ids":[]},"category":"239","private_review_ids":[201],"public_review_ids":[]}]` – CHarris Apr 03 '18 at 23:15
  • Sorry, my bad. I completely missed that. I've added the `category` index, and added a call to `array_values`. See my updated answer. – fubar Apr 03 '18 at 23:18
  • I was getting `"category":null` but I changed in your code `$reviews[$cat_id]['category'] = $category_id;` to `$reviews[$cat_id]['category'] = $cat_id;` and it's working better. So now I'm getting like `[{"category":7,"public_review_ids":["91"],"private_review_ids":[134,91]},{"category":260,"public_review_ids":["223"],"private_review_ids":[97]}]`Still though, how can I get, if the value is in both `private_review_ids` and `public_review_ids`, to just appear in `private_review_ids` key? For instance, it should be `{"category":7,"public_review_ids":[],"private_review_ids":[134,91]}` – CHarris Apr 03 '18 at 23:37
  • Okay, I've refactored my answer to handle the private reviews first. Then when handling the public reviews, it checks if the review id exists in the private review ids array before adding it to the public review ids array. – fubar Apr 03 '18 at 23:44
  • @CHarris, how'd you go? – fubar Apr 04 '18 at 02:52
  • Sorry, had to go. Different timezones:) Excellent! Works perfect, tx for your help. – CHarris Apr 04 '18 at 08:08