For example i have two tables:
PRODUCTS (id, category_id, name);
CATEGORIES (id, name);
I want pass to frontend JSON like:
"categoryProjects": [
{
"id" : 1,
"name" : "some category name",
"projects": [
{
"id": 1,
"name": "Product1"
},
{
"id": 2,
"name": "Product2"
},
[
},
{
"id" : 2,
"name" : "second category name",
"projects": [
{
"id": 3,
"name": "Product3"
}
[
}
]
My question is: What is the best way to do this? I want it to be as efficient as possible. I have simple server in php, database (mysql), and I want create API. I wonder what is the best way to do endpoint for my frontend.
You'd need to do a SQL join, like so
select products.*, categories.name as category from products left join categories on products.category_id = categories.id
Then map the returned table to a PHP array and convert it to JSON.
<?php
$sth = $pdo->query("select products.*, categories.name as category from products left join categories on products.category_id = categories.id");
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
$categories = [];
foreach ($rows as $row)
{
if (!isset($categories[$row['category_id']]))
{
$categories[$row['category_id']] = [
"name" => $row['category'],
"id" => $row['category_id'],
"products" => []
];
}
$categories[$row['category_id']]['products'][] = [
"id" => $row['id'],
'name' => $row['name']
];
}
print json_encode($categories, JSON_PRETTY_PRINT);
This code will run assuming your tables were built as you described them.
Related
I am trying to implement a new way for users to enter data into an HTML form with Slim Select JS library.
I have basic functionality working, with a pre-populated list of <option> items.
Originally, the PHP code would grab the list of names from a database (now in MongoDB), which is then looped through when the <select> element is created.
With Slim Select, you can pass in a "data array" as a parameter of the JS script. The manually-created format is this:
var jsPlayers2 = [
{"placeholder": true, "text": "Type Name"},
{"text": "Ernie Els", "value": "abc1"},
{"text": "Rory McIlroy", "value": "abc2"},
{"text": "Tiger Woods", "value": "abc3"}
];
new SlimSelect({
select: '#slim-select',
data: jsPlayers2, // THIS WOULD BE REPOINTED TO THE JSPLAYERS ARRAY VAR...
onChange: (info) => {
console.log(info)
}
})
My MongoDB document structure returned currently is:
var jsPlayers = [{
"_id": {
"$oid": "62b49410e63c2f8469089189"
},
"name": "Tiger Woods",
"clubs": [{
"clubId": {
"$oid": "6076030465508936f00e086c"
},
"name": "Jupiter FL",
"nickName": "Jupiter",
"logoPath": "jupiter.png"
}]
}, {
"_id": {
"$oid": "609d0993906429612483cfb1"
},
"name": "Ernie Els",
"clubs": [{
"clubId": {
"$oid": "6076030465508936f00e086c"
},
"name": "Wentworth UK",
"nickName": "Wentworth",
"logoPath": "wentworth.png"
}]
}, ...
}];
I have used a simplistic echo of this variable into a new JS variable:
var jsPlayers = <?php echo json_encode($players); ?>;
How can I only pick out the fields I need from within each document? Or is there a way to filter the array elements when I add them to the slim-select.data property?
You need to loop through your players to create the array you want to output as JSON. Something like this:
$options = [];
foreach ($players as $player) {
$options[] = (object)["text" => $player->name,
"value" => $player->getId()];
}
echo json_encode($options);
This only outputs the JSON.
Note that I used $player->getId(), which might not work for you. If your players are really objects you might have defined a method yourself to get their id.
I have two collections. One to store all the user Details and another to store movies. I have a user_id field which has the objectId of the user who uploads it in the movie collection.
Now I need to store all the movie ObjectId's as a array in the corresponding user collection. Like one to many relationship.
say,
I have some movie documents :
[{
'id' : '1',
'title' : 'Pk',
'user_id' : '25'
},
{
'id' : '2',
'title' : 'Master',
'user_id' : '25'
}]
In user collection, I want to store all the Movie_id's as a array to the corresponding user.
{
'user_id' : '25',
'user_name' : 'john',
'Movie_ids' : ['1','2']
}
How can I achieve this using mongodb and express.js?
Query
$lookup does what you want (see mongodb documentation is very good)
$map is used to keep only the ids in the array
Test code here
db.users.aggregate([
{
"$lookup": {
"from": "movies",
"localField": "user_id",
"foreignField": "user_id",
"as": "movies"
}
},
{
"$set": {
"movies": {
"$map": {
"input": "$movies",
"in": "$$this.id"
}
}
}
}
])
Ok, I'm not sure if this is entirely what you are looking for but you can use javascript function .filter on the movie object to get all the movies with user_id=25 and then map the id's of those movies to a new array like this:
let movies = [
{
"id": "1",
"name": "pk",
"user_id": "25"
},{
"id": "2",
"name": "Master",
"user_id": "25"
}]
let user = {
"id": "25",
"name": "john"
}
let sortedMovies = movies.filter(movie => movie.user_id === user.id).map(movie => movie.id);
user.movieIDs = sortedMovies;
A link to test the code: https://playcode.io/816962/
Pretty much my data looks something like this:
{
"name" : "Name1",
"monthson" : "4",
"data" : "OLD DATA FOR 1"
},
{
"name" : "Name1",
"monthson" : "5",
"data" : "LATEST DATA FOR 1"
},
{
"name" : "Name2",
"monthson" : "7",
"data" : "OLD DATA FOR 2"
},
{
"name" : "Name2",
"monthson" : "8",
"data" : "LATEST DATA FOR 2"
}
I'm trying to figure out a way to group everything by each name and then output the latest Data. (monthson represents how many months each set has been active so the highest monthson is the most recent).
My Mongo query looks something like this:
db.collection.aggregate(
[
{$match: {$in: ["name1", "name2"]}}
{$group:
{
_id:"$name",
monthson:{$max: "$monthson"},
data: {$addToSet: "$data"}
}},
])
The output looks like this:
{
_id:"Name1",
monthson: 5,
data: ["OLD DATA FOR 1", " LATEST DATA FOR 1"]
}
{
_id:"Name2",
monthson: 8,
data: ["LATEST DATA FOR 2", "OLD DATA FOR 2"]
}
The trick is every time I run this query it adds every set of data to my result when I only want the data that corresponds to the highest monthson. I can't query for first, last or highest data because they will always be in random order.
You can use $sort to get the order you want (I used oldest first), and then $first to get to the first (oldest) matching record for each "name":
db.collection.aggregate([
{
$match: {name: {$in: ["Name1", "Name2"]}}
},
{
$sort: {monthson:-1}
},
{
$group: {
_id:"$name",
first:{$first: "$$ROOT"}
}
}
])
I want to display data(json) in my site using AngularJs . here's what i did :
Create a database in phpmyAdmin .
Create a table with 2 row , subject and body . Should i create an id ?
After doing with PHP and angular , I got JSON like this :
[{
"0":"Soheil","subject":"Soheil",
"1":"Sadeghbayan","body":"Sadeghbayan"}
,{"0":"","subject":"","1":"","body":""}
,{"0":"","subject":"","1":"","body":""}
,{"0":"dasdasd","subject":"dasdasd","1":"qe","body":"qe"}
,{"0":"Hello","subject":"Hello","1":"This is chandler !","body":"This is chandler !"}
,{"0":"","subject":"","1":"","body":""},
{"0":"Something new in website","subject":"Something new in website","1":"oh Awsome !","body":"oh Awsome !"
}]
I think this is invalid JSON because when I replace it with custom JSON that I wrote it work .
Json valid
{
"fruits": [
{
"id": "1",
"name": "Apple"
},
{
"id": "2",
"name": "Orange"
}
]
}
AngularJS
var fruitsApp = angular.module('fruitsApp', []);
fruitsApp.factory('fruitsFactory', function($http) {
return {
getFruitsAsync: function(callback) {
$http.get('fruits.json').success(callback);
}
};
});
fruitsApp.controller('fruitsController', function($scope, fruitsFactory) {
fruitsFactory.getFruitsAsync(function(results) {
console.log('fruitsController async returned value');
$scope.fruits = results.fruits;
});
});
Html
<ul>
<li ng-repeat="fruit in fruits">
{{fruit.subject}} is {{fruit.body}}
</li>
</ul>
php
include('config.php');
$data = json_decode(file_get_contents("php://input"));
$subject = mysql_real_escape_string($data->subject);
$body = mysql_real_escape_string($data->body);
mysql_select_db("angular") or die(mysql_error());
mysql_query("INSERT INTO newstory (subject,body) VALUES ('$subject', '$body')");
Print "Your information has been successfully added to the database.";
$query = "SELECT * FROM newstory";
$result = mysql_query($query);
$arr = array();
while ($row = mysql_fetch_array($result)) {
$subject = $row['subject'];
$body = $row['body'];
$arr[] = $row;
}
echo json_encode($arr);
Any idea ? Thx in advance
Your JSON is a valid. Refer to this for information on JSON and this to check/validate a JSON object.
The data coming back from your $http.get / database data does not have a fruits attribute and you expect that when you set your $scope.fruits (the below snippet is taken from your code):
$scope.fruits = results.fruits;
The structure of the data that is being returned by the $http.get call is different than the format of your sample data.
Here's your $http.get / database data (I shortened it for brevity):
[
{
"0": "Soheil",
"1": "Sadeghbayan",
"subject": "Soheil",
"body": "Sadeghbayan"
},
{
"0": "Hello",
"1": "This is chandler !",
"subject": "Hello",
"body": "This is chandler !"
},
{
"0": "",
"1": "",
"subject": "",
"body": ""
}
]
And here's your sample / mock data:
{
"fruits": [
{
"id": "1",
"name": "Apple"
},
{
"id": "2",
"name": "Orange"
}
]
}
The former is an array of objects with keys: 0, 1, subject and body.
The latter is an object with keys: fruits.
They are both valid JSON objects with different object structures. But, you expect a fruits attribute where there isn't one. Also, your HTML/UI might be expecting the data format to look like what is in your mock data. So check that too.
I'm using CakePHP to query my database table 'Task' that includes project_id, id, parent_id, title, description. My controller code handles the query like so:
$query= $this->Task->find('threaded', array(
'conditions' => array(
'Task.project_id' => 83,
),
'fields' => array(
'Task.id',
'Task.title',
'Task.parent_id',
)
));
//Pass the result to the view
$this->set('query', $query);
Then in my view, if I decode the json with the following:
<?php echo json_encode($simple); ?>
I get the following json structure:
[
{
"Task": {
"id": "475",
"title": "Have a Picnic",
"parent_id": "0"
},
"children": [
{
"Task": {
"id": "476",
"title": "Drive/Hike to Moutains",
"parent_id": "475"
},
"children": []
}
]
}
]
(I used this tool in to beautify it, the output is of course a continuous string)
But JS JIT SpaceTree requires the following structure:
{
"id": "aUniqueIdentifier",
"name": "usually a nodes name",
"data": [
{key:"some key", value: "some value"},
{key:"some other key", value: "some other value"}
],
children: [/* other nodes or empty */]
}
And I have no idea how to either adjust the output, or change my query to return the correct structure. Also, I've tried both 'threaded' and 'list' find() types and get the same structure. Any help is greatly appreiciated!
Simply iterate over the results and map the data into your desired structure, that's a pretty basic task. You could do that in the controller, in the view (maybe using a helper), or even in the model using a custom find method.
Here's a simple example. I don't know what data is good for, also there are no further fields in your result, so I've left that part.
function mapThreaded($source, &$target)
{
foreach($source as $item)
{
$node = array
(
'id' => $item['Task']['id'],
'name' => $item['Task']['title'],
'children' => array()
);
if(count($item['children']))
{
mapThreaded($item['children'], $node['children']);
}
$target[] = $node;
}
}
$tasks = $this->Task->find('threaded', array(...));
$tree = array();
mapThreaded($tasks, $tree);
pr($tree);
pr(json_encode($tree, JSON_PRETTY_PRINT)); // pretty print requires PHP >= 5.4.0
It should result in a JSON structure like this:
[
{
"id": "475",
"name": "Have a Picnic",
"children": [
{
"id": "476",
"name": "Drive/Hike to Moutains",
"children": [
]
}
]
}
]
In case Spacetree supports only a single root elment, simply use current($tree) or in JavaScript pass the first array entry to Spacetree.