Json encode for nested data using PDO PHP - php

I have following tables:
+---------+-----------+ +----------+---------+-------------+
| item_id | item_name | | image_id | item_id | image_url |
+---------+-----------+ +----------+---------+-------------+
| 1 | phone | | 1 | 1 | http://url1 |
| 2 | computer | | 2 | 1 | http://url2 |
| 3 | keyboard | | 3 | 2 | http://url2 |
+---------+-----------+ +----------+---------+-------------+
What should I do in php using PDO and json encode to have the following ouput:
[
{
"item_id":"1",
"name":"phone",
"images": [
{
"image_id":"1",
"url":"http://url1"
},
{
"image_id":"2",
"url":"http://url2"
}
]
},
{
"item_id":"2",
"name":"computer",
"images": [
{
"image_id":"3",
"url":"http://url3"
}
]
},
{
"item_id":"3",
"name":"keyboard",
"images": []
}
]
Do I HAVE to use foreach inside foreach loop to get this result?

No, use a single loop, and a single SQL query.
Firstly the SQL query is
SELECT im.image_id, im.image_url, im.item_id
it.item_name
FROM images im
LEFT JOIN items it ON it.item_id=im.item_id
ORDER BY im.item_id, im.image_id
And your PHP (paraphrased) is:
$lastItemId = -1;
$aJson = array();
while ($row = GetNextRow()) { // Depends on your class
$itemID = $row['item_id'];
if (!isset($aJson[$itemID])) {
$aJson[$itemID] = array('item_id'=$itemID, 'item_name'=$row['item_name'], images=>array());
}
$aJson[$itemID]['images'] = array('image_id'=>$row['image_id'], 'image_url'=>$row['image_url']);
}
echo json_encode($aJson);
You should be able to tweak from there?

Related

Generating JSON Query Result in Codeigniter

So i have database table named usermeta and have table structure like this :
-----------------------------------------------------------
| ummeta_id | user_id | meta_key | meta_value |
-----------------------------------------------------------
| 1 | 1 | fullname | John Doe |
| 2 | 1 | birthplace | New York |
| 3 | 1 | birthdate | 1990/01/01 |
| 4 | 1 | mobile | 0812-3456-7890 |
| 5 | 1 | email | john.doe#mail.com |
| 6 | 2 | fullname | Jon Wick |
| 7 | 2 | birthplace | Washington DC |
| 8 | 2 | birthdate | 1985/10/21 |
| 9 | 2 | mobile | 0890-1234-5678 |
| 10 | 2 | email | wickjohn#mail.com |
And i try to generate json data for all data from this database using Codeigniter (v 3.1.9) using Controller and Model.
This is my Model (model name: db_usermeta)
function userslist()
{
$query = $this->db->select('*')
->from('usermeta')
->get();
return $query->result();
}
This is my Controller
public function userlist()
{
header('Content-Type: application/json; charset=utf-8');
$query = $this->db_usermeta->userslist();
$json_data = array();
foreach ($query as $key)
{
$json_data[$key->meta_key] = $key->meta_value;
}
echo json_encode($json_data);
}
The result when i open using my browser to check the json data using web developer tool is only show last record, in this case only show data from user_id 2, like this:
{
"fullname":"John Wick",
"birthplace":"Washinton DC",
"birthdate":"1985/10/21",
"mobile":"0890-1234-5678",
"email":"wickjohn#mail.com"
}
What I want to achieve is to show all json data nested like this:
"data": [
{
"fullname":"John Doe",
"birthplace":"New York",
"birthdate":"1990/01/01",
"mobile":"0812-3456-7890",
"email":"john.doe#mail.com"
},
{
"fullname":"John Wick",
"birthplace":"Washinton DC",
"birthdate":"1985/10/21",
"mobile":"0890-1234-5678",
"email":"wickjohn#mail.com"
}
]
How can i achieve this? Did I make a mistake on my controller and model. I really appreciate your help.
your $key->meta_key is overwriting for every record. that's why only last record appeared. You don't actually need to loop through to get json data.
public function userlist()
{
header('Content-Type: application/json; charset=utf-8');
$query = $this->db_usermeta->userslist();
$json_data = array(array());
$user_id_map = array();
$index = 0;
foreach ($query as $key)
{
if(!isset($user_id_map[$key->user_id])){
$user_id_map[$key->user_id] = $index++;
}
$currentIndex = $user_id_map[$key->user_id];
$json_data[$currentIndex][$key->meta_key] = $key->meta_value;
}
echo json_encode($json_data);
}
just change your controller code to this and this will return json data.
Since the meta key fullname is same for both records, you need to change the key name to something unique
foreach ($query as $key)
{
$json_data[$key->meta_key] = $key->meta_value;
}
Change $json_data[$key->meta_key] to $json_data[$key->meta_key.$key->user_id]
or simply change it to $json_data[$key->ummeta_id]

From MYSQL result to JSON: unable to create right JSON

I have this results from MySQL:
+-----------------+----------+-----------------+
| SUPPLIED_AMOUNT | DATE_ISO | DATE_JAVASCRIPT |
+-----------------+----------+-----------------+
| 5919.00 | 20150716 | 1436994000000 |
| 4389.00 | 20150717 | 1437080400000 |
| 12069.00 | 20150718 | 1437166800000 |
| 10220.00 | 20150720 | 1437339600000 |
| 9444.00 | 20150721 | 1437426000000 |
| 8630.00 | 20150722 | 1437512400000 |
| 9009.00 | 20150723 | 1437598800000 |
| 7324.00 | 20150724 | 1437685200000 |
| 4295.00 | 20150725 | 1437771600000 |
| 4398.00 | 20150726 | 1437858000000 |
| 3385.00 | 20150727 | 1437944400000 |
+-----------------+----------+-----------------+
I need to convert to a similar json:
[1253145600000,26.36],
[1253232000000,26.43],
[1253491200000,26.29],
[1253577600000,26.35],
[1253664000000,26.50]
This is my current PHP code:
$supplied = $service->getSupplied();
if (count($supplied)>0) {
foreach ($supplied as $key=>$value) {
$chart_data['data'][] = $value['DATE_JAVASCRIPT'].','.$value['SUPPLIED_AMOUNT'];
}
}
But it render a similar JSON:
"data": [
"1437004800000,5919.00",
"1437091200000,4389.00",
"1437177600000,12069.00",
"1437350400000,10220.00",
"1437436800000,9444.00"]
Thank you very much
Don't put ['data'] into your array, then:
$chart_data[] = array($value['DATE_JAVASCRIPT'],$value['SUPPLIED_AMOUNT']);
^^^^
And note the change to array(). You're embedding what amounts to CSV strings in your array, which seems weird...
This part of code should work:
foreach ($supplied as $key=>$value) {
$chart_data[] = [$value['DATE_JAVASCRIPT'],$value['SUPPLIED_AMOUNT']];
}
$chart_data['data'][] = [$value['DATE_JAVASCRIPT'].','.$value['SUPPLIED_AMOUNT']];
If you don't need 'data':
$chart_data[] = [$value['DATE_JAVASCRIPT'].','.$value['SUPPLIED_AMOUNT']];
You should take part of json_encode, by formatting your array and using this function to take back a well formatted JSON file. It will avoid some code misconception and errors :
$supplied = $service->getSupplied();
if (count($supplied)>0) {
foreach ($supplied as $key=>$value) {
$date = $value['DATE_JAVASCRIPT'];
$supplied_amount = $value['SUPPLIED_AMOUNT'];
$chart_data[] = [$date, $supplied_amount];
}
$chart_data = json_encode($chart_data);
print_r($chart_data);
# chart_data : example of JSON output
# [
# [12092016, 12.80],
# [12122016, 57.90],
# [12112016, 48.81]
# ]
}

How to map matched records returned from a join instead of separate rows

Scenario :
I have two tables, structured as following.
Table 1 : images
+--------+------------+
| img_id | img_name |
+--------+------------+
| 1 | image1.jpg |
| 2 | image2.jpg |
| 3 | image3.jpg |
+--------+------------+
Table 2 : image_tags
+---------+--------+----------+--------+--------+
| cord_id | img_id | tag_text | xcord | ycord |
+---------+--------+----------+--------+--------+
| 1 | 1 | Tag1 | 28.1 | 30.4 |
| 2 | 1 | Test Tag | 23.4 | 4.5 |
+---------+--------+----------+--------+--------+
Now i want the images along with their tags which is quite simple using the left join
SELECT img_id, img_name,tag_text, xcord,ycord FROM images t1 LEFT JOIN image_tags t2 ON t1.id=t2.id
This query results in the following data set
+--------+------------+----------+--------+--------+
| img_id | img_name | tag_text | xcord | ycord |
+--------+------------+----------+--------+--------+
| 1 | image1.jpg | Tag1 | 28.1 | 30.4 |
| 1 | image1.jpg | Test Tag | 23.4 | 4.5 |
| 2 | image2.jpg | NULL | NULL | NULL |
| 3 | image3.jpg | NULL | NULL | NULL |
+--------+------------+----------+--------+--------+
Problem :
Now using PHP (or MYSQL if possible), i want the results from the image_tags table to be concatenated with each row in form of an array.
So that when i loop through the records in Angular, i have images along with their tags in form of an array instead of two separate rows as you can see the first two rows in the result set.
Desired result example,
{
cord_id : 1,
img_id : 1,
tags : [{
tag_text : "Tag1",
xcord : 28.1,
ycord : 30.4,
},{
tag_text : "Test Tag",
xcord : 23.4,
ycord : 4.5,
}
]
}
I have studied about map() function in PHP but unable to achieve this.
Note: I am using Codeigniter, so if that has some relevant support to achieve this, that would also work for me.
Any help would be highly appreciated. Thanks
It is possible to do it with just one query.
Since you have a unique ID you can use it as an index for your array.
$images = array();
foreach($queryResults as $result){
if(!isset($images[$result['img_id']])){
$images[$result['img_id']] = array();
$images[$result['img_id']]['cord_id'] = $result['cord_id'];
$images[$result['img_id']]['img_id'] = $result['img_id'];
$images[$result['img_id']]['tags'] = array();
}
$tag = array(
'tag_text'=>$result['tag_text'],
'xcord'=> $result['xcord'],
'ycord'=> $result['ycord']
);
$images[$result['img_id']]['tags'][] = $tag;
}

Dump data in json format from two tables from MySQL

I have the following scenario.
I have 2 tables as follow
Table 1
ID, Name, Desc, Seo
Table 2
ID, Table1_ID, Relation_Table1_ID
in Table 1 I have all my data that I need as:
-----------------------------------
|ID | Name |Desc |Seo |
-----------------------------------
| 1 | Smith |Father |f |
| 2 | Jonh |Son |j |
| 3 | Margat |Mother |m |
| 4 | Bis3 |son |b1 |
| 5 | Bis2 |son |b2 |
| 6 | Bis1 |son |b3 |
| 7 | Lanos |Brother |l |
-----------------------------------
And then we have our table 2 as follow
-------------------------------------
|ID | Table1_ID |Relation_Table1_id|
--------------------------------------
| 1 | 1 | 4 |
| 2 | 1 | 5 |
| 3 | 3 | 6 |
| 4 | 3 | 2 |
| 5 | 7 | 0 |
--------------------------------------
So far I have my first table dump with jSON() as follow:
<?php
include ('config.php');
$dump1 = mysql_query("SELECT * FROM Table1 ") or die(mysql_error());
$getList = array();
while ($row = mysql_fetch_assoc($dump1)) {
$getList[] = $row;
}
print json_encode($getList); exit;
?>
That code will give me the following:
[
{
"ID":"1",
"Name":"Smith",
"Desc":"Father",
"Seo":"f"
},
{
"ID":"2",
"Name":"Jonh",
"Desc":"Son",
"Seo":"j"
},
{
"ID":"3",
"Name":"Margat",
"Desc":"Mother",
"Seo":"m"
}... ... ...
]
What I can't figure is how do I get the following
[
{
"ID":"1",
"Name":"Smith",
"Desc":"Father",
"Seo":"f",
"Relations":[
{
"ID":"4",
"Name":"Bis3",
"Desc":"Son",
"Seo":"b1"
}
]
},
{
"ID":"3",
"Name":"Margat",
"Desc":"Father",
"Seo":"f",
"Relations":[
{
"ID":"6",
"Name":"Bis2",
"Desc":"Son",
"Seo":"b2"
},
{
"ID":"2",
"Name":"Jonh",
"Desc":"Son",
"Seo":"j"
}
]
}... ... ...
]
In plain text it would be something like
ID 1 Smith
| |_ID 4 Bis3
|
|_ ID 3 Margat
|_ID 5 Bis2
|_ID 2 Jonh
I'm learning how to use json and I just got the first part as you can see, but my lack of knowledge of SQL and php wont let me get the what I really want, so please can any one help me achieve this scenario please.
Thank you.
you can loop through $getlist
then query
for($i = 0; $i <= count($getlist); $i++){
"SELECT * FROM Table2 WHERE Table1_ID = $getlist[$i]['ID']"
// get the result however way
$getlist[$i]['something'] = $result;
}
then take the result of that, inside the loop, and assign it to whichever key of getlist you want
for example
hopefully thats specific enough. let me know if you have problems with that.
You need to join across the two tables. First, join the second table with the first table. This can be done with the following code:
select * from table_2 as t2 join table_1 as t1 on t1.id = t2.rel_id;
which results in:
+------+-----------+--------+------+------+------+------+
| ID | table1_id | rel_id | ID | name | desc | seo |
+------+-----------+--------+------+------+------+------+
| 4 | 3 | 2 | 2 | John | Son | j |
| 1 | 1 | 4 | 4 | Bis3 | son | b1 |
| 2 | 1 | 5 | 5 | Bis2 | son | b2 |
| 3 | 3 | 6 | 6 | Bis1 | son | b3 |
+------+-----------+--------+------+------+------+------+
now we want to join the columns if the table1_id is the same. This can be done with the GROUP_CONCAT command:
select table1_id,group_concat(t1.name) as name_rel,
group_concat(t1.desc) as desc_rel, group_concat(seo) as seo_rel,
group_concat(rel_id) as id_rel from table_2 as t2 join table_1 as t1 on
t2.rel_id = t1.id group by t2.table1_id
which results in:
+-----------+-----------+----------+---------+--------+
| table1_id | name_rel | desc_rel | seo_rel | id_rel |
+-----------+-----------+----------+---------+--------+
| 1 | Bis2,Bis3 | son,son | b2,b1 | 5,4 |
| 3 | John,Bis1 | Son,son | j,b3 | 2,6 |
+-----------+-----------+----------+---------+--------+
The as command can be used to rename columns in the output. Try running the query without it and you should see column names like group_concat(t1.name) instead of name_rel.
Now we want to join this selection with table_1 where the table1_id is the same as the id in table1. This can be done with the following query:
select * from (
select table1_id,group_concat(t1.name) as name_rel,
group_concat(t1.desc) as desc_rel, group_concat(seo) as seo_rel,
group_concat(rel_id) as id_rel from table_2 as t2 join table_1 as t1 on
t2.rel_id = t1.id group by t2.table1_id
) as joined_table
join table_1 as t3 on t3.id = joined_table.table1_id;
which results in:
+-----------+-----------+----------+---------+--------+------+--------+--------+------+
| table1_id | name_rel | desc_rel | seo_rel | id_rel | ID | name | desc | seo |
+-----------+-----------+----------+---------+--------+------+--------+--------+------+
| 1 | Bis2,Bis3 | son,son | b2,b1 | 5,4 | 1 | Smith | Father | f |
| 3 | John,Bis1 | Son,son | j,b3 | 2,6 | 3 | Margat | Mother | m |
+-----------+-----------+----------+---------+--------+------+--------+--------+------+
As you can see, you know have all the data. All that is left is to turn the *_rel columns into separate objects, which can be done in php. Go ahead and give that a shot. I've gotta go for now, but I'll edit this post later if you're still having trouble.
Alright, I'm back. My php is rusty, but something along these lines should work:
while ($row = mysql_fetch_assoc($dump1)) {
$name_rel = explode("," , $row["name_rel"]);
$desc_rel = explode("," , $row["desc_rel"]);
$seo_rel = explode("," , $row["seo_rel"]);
$id_rel = explode("," , $row["id_rel"]);
$relations = array();
for($i = 0; $i < count($id_rel); ++$i){
$temp = array("ID" => $id_rel[$i],
"Name" => $name_rel[$i],
"Desc" => $desc_rel[$i],
"Seo" => $seo_rel[$i],);
$relations[] = $temp ;
}
unset($row["id_rel"]);
unset($row["name_rel"]);
unset($row["desc_rel"]);
unset($row["seo_rel"]);
$row["Relations"] = $relations ;
$getList[] = $row;
}
print json_encode($getList); exit;
This will create each of the Relations objects and add them to the row. The unset commands should remove the keys we no longer care about (id_rel, name_rel, desc_rel, and seo_rel). We no longer care about them because their data should have been moved to the Relations object.

PDO Query from Results of Another PDO Query

I have this code which hits a view in mysql called vAlbums this returns a JSON array of the query results
function getAlbumPics($arno){
$aSql = "SELECT albu_ablumid, albu_name_en, albu_name_de, albu_name_fr, albu_name_nl, albu_name_es, albu_name_it, albu_photourl FROM vAlbums WHERE site_arno=:arno";
try {
$db = getConnection();
$aStmt = $db->prepare($aSql);
$aStmt->bindParam(":arno",$arno);
$aStmt->execute();
$albums = $aStmt->fetchAll(PDO::FETCH_OBJ);
$arrAID = $aStmt->fetchColumn(2);
$db = null;
echo '{"albums": ' . json_encode($albums) . '}';
} catch(PDOException $e) {
echo '{"error":[{"text":"'. $e->getMessage() .'"}],';
echo '"SQL": ' . json_encode($aSql) .'}';
}
}
I need to do a sub query to place an array of photos in each album in the array like thus
{
"albums": [
{
"albu_ablumid": "1",
"photos": [
{
"photourl": "photo1"
},
{
"photourl": "photo2"
},
{
"photourl": "photo3"
}
]
},
{
"albu_ablumid": "2",
"photos": [
{
"photourl": "photo1"
},
{
"photourl": "photo2"
},
{
"photourl": "photo3"
}
]
}
]
}
Can someone show how to achieve this the MySQL query for photos is:
SELECT * FROM photos WHERE album_id = x
Thanks
Why not just do a join and group concat in a single query?
SELECT
albu_ablumid,
albu_name_en,
albu_name_de,
albu_name_fr,
albu_name_nl,
albu_name_es,
albu_name_it,
albu_photourl,
group_concat(photourl) // Guessing at column Name
FROM
vAlbums a
join photos b
on a.albu_ablumid=b.album_id
WHERE
site_arno=:arno
group by
albu_ablumid,
albu_name_en,
albu_name_de,
albu_name_fr,
albu_name_nl,
albu_name_es,
albu_name_it,
albu_photourl
This will return all the photos in a comma separated string in each row that matches the album. You can then easily split it up as needed in your code. It saves a lot of connections and multiple queries being run.
Here is a little example from my play db to show how it functions:
mysql> select * from table1;
+---------+------+------+-------------+
| autonum | ID | name | metavalue |
+---------+------+------+-------------+
| 1 | 1 | Rose | Drinker |
| 2 | 1 | Rose | Nice Person |
| 3 | 1 | Rose | Runner |
| 4 | 2 | Gary | Player |
| 5 | 2 | Gary | Funny |
| 6 | 2 | Gary | NULL |
| 7 | 2 | Gary | Smelly |
+---------+------+------+-------------+
7 rows in set (0.00 sec)
mysql> select ID, group_concat(metavalue) from table1 group by ID;
+------+----------------------------+
| ID | group_concat(metavalue) |
+------+----------------------------+
| 1 | Drinker,Nice Person,Runner |
| 2 | Player,Funny,Smelly |
+------+----------------------------+
2 rows in set (0.00 sec)
and with some simple code to take care of the NULLs if you need to for some reason:
mysql> select ID, group_concat(coalesce(metavalue,'Empty')) from table1 group by ID;
+------+-------------------------------------------+
| ID | group_concat(coalesce(metavalue,'Empty')) |
+------+-------------------------------------------+
| 1 | Drinker,Nice Person,Runner |
| 2 | Player,Funny,Empty,Smelly |
+------+-------------------------------------------+
2 rows in set (0.00 sec)

Categories