I don't know why when I echo json_encode a query result set I get the number of the result row before each object. I just want to count the number of total rows returns and have them displayed only once in the beginning of the JSON string and then just the rows returns afterwards. I.e. using the following code:
//...active record query
$result = $this->db->get();
$data = array();
$count = 1;
foreach($result->result() as $row)
{
$data['count'] = $count;
$entry = array();
$entry['firstname'] = $row->first_name;
$entry['lastname'] = $row->last_name;
$entry['jobtitle'] = $row->title;
$entry['dept'] = $row->dept_name;
$entry['deptid'] = $row->dept_no;
if($row->emp_no == null)
{
$entry['ismanager'] = 0;
}
else
{
$entry['ismanager'] = 1;
}
$data[] = $entry;
$count++;
}
return $data;
and then json_encode it in the controller, I get:
{"count":35,"0":{"firstname":"Georgi","lastname":"Facello","jobtitle":"Senior Engineer","dept":"Development","deptid":"d005","ismanager":0},"1":{"firstname":"Kirk","lastname":"Facello","jobtitle":"Senior Engineer","dept":"Development","deptid":"d005","ismanager":0},....rest of the query results
What I don't want is the "0" and "1" etc, before the row results. I already have the total count of the returned results so I don't need the individual row numbers.
If someone could kindly help me out I would appreciate it, thanks.
If you try to serialize an array as JSON, it would become something like this:
[elem1, elem2, elem3, ...]
But if that "array" have other fields then it will be serialized as an object:
{"field":value, "0":elem1, "1":elem2, "2":elem3, ...}
Since there's no way to serialize field using the array syntax, and json_encode can not simply discard it, then it uses the object syntax. As stated in the docs:
Note:
When encoding an array, if the keys are not a continuous numeric sequence starting from 0, all keys are encoded as strings, and specified explicitly for each key-value pair.
A possible workaround for this would be separating the count from the list of elements:
$data = array();
$list = array();
$data['list'] = list;
$count = 1;
foreach($result->result() as $row)
{
$data['count'] = $count;
$entry = array();
...
$list[] = $entry;
$count++;
}
That would serialize to something like:
{"count":35,"list":[{"firstname":"Georgi","lastname":"Facello","jobtitle":"Senior Engineer","dept":"Development","deptid":"d005","ismanager":0},{"firstname":"Kirk","lastname":"Facello","jobtitle":"Senior Engineer","dept":"Development","deptid":"d005","ismanager":0},....rest of the query results]}
It looks like you might be using JSON_FORCE_OBJECT on your json_encode which will always make your numerical index show up as a property. You should show your json_encode step in your question.
If you turn option off and go with a default encoding, you will still need to nest your numerically indexed array in its own property or the numerical indexes will show up as properties in order to make valid JSON. For perhaps do something like this when assigning your rows to the object:
$data['records'][] = $entry;
Related
i have question i don't know better approach to do it in mysql. I have a table in mysql with list of regex's each regex represent a company order number
i want to be able to compare a number to that list to get which company this number belongs to. the lazy way is to list all the regex in php and then using loop to get the company , but i want to do this using the power of mysql .
Like #Mech mention this might be vague.
i will try to explain it more :
I have two tables table with actual regex pattern in plain text in a column like "^[8]{1}[0-9]{10}$"
and this pattern belong to a company , there is more than 500 regex patterns .
Thank you.
Here you go #BM2ilabs. A function as requested :)
carrierID(88888141234);
function carrierID($ordernum) {
// create a connection to your db here
// fetch data needed for loop
$sql = "SELECT regex, carrier_id FROM `company_tbl_from_image`";
// fetch results
$results = $conn->query($sql);
// loop through $results
foreach ($results as $result) {
// individually check against each regex in the table
$regex = $result[regex];
// find first instance of $regex, where the $ordernum is unique, there should only be one match
if (preg_match('/'.$regex.'/', $ordernum)) {
$carrier_id = $result[carrier_id];
break; // remove break to show other matches
}
}
// check if $carrier_id is empty
if ($carrier_id <> "") {
echo $carrier_id;
} else {
echo "No carrier ID found.";
}
}
MySQL only option. Just search this:
SELECT carrier_id FROM `company_tbl_from_image` WHERE 'order number' REGEXP regex
I'm writing a Perl script that is meant to deal with an API which returns metrics about a set of URLs that I pull from MySQL then post these metrics back into a different table. Currently this piece of code:
my $content = $response->content;
my $jsontext = json_to_perl($content);
my $adsql = 'INSERT INTO moz (url_id,page_authority,domain_authority,links,MozRank_URL,MozRank_Subdomain,external_equity_links) VALUES (?,?,?,?,?,?,?)';
my $adrs = $db->prepare( $adsql );
my $adsql2 = 'UPDATE url
SET moz_crawl_date = NOW()
where url_id = ?;';
my $adrs2 = $db->prepare( $adsql2 );
my $currentUrlId = 0;
foreach my $row (#$jsontext){
$adrs->execute($url_ids[$currentUrlId], $row->{'fmrp'}, $row->{'upa'}, $row->{'pda'}, $row->{'uid'}, $row->{'umrp'}, $row->{'ueid'});# || &die_clean("Couldn't execute\n$adsql\n".$db->errstr."\n" );
$adrs2->execute($url_ids[$currentUrlId]);
$currentUrlId++;
}
is throwing this error:
Not an ARRAY reference at ./moz2.pl line 124.
this is line 124:
foreach my $row (#$jsontext){
this whole chunk of code is in a while loop. I am actually able to iterate a couple times and fill my MySQL table before the script fails (technically the program works, but I don't want to just leave an error in it).
Anybody have any suggestions?
Perl gave you the correct answer
Not an ARRAY reference: #$jsontext
You are dereferencing $jsontext, which is the result of json_to_perl(string), to an array.
But json_to_perl() didn't return an arrayref.
json_to_perl seems to be from this API: http://search.cpan.org/~bkb/JSON-Parse-0.31/lib/JSON/Parse.pod#json_to_perl
which returns according to the doc either an arrayref or a hashref.
Apparently it did return a hashref in your case, so you have to add the logic to deal with the HASH case. Which seems to be a single row.
if (ref $jsontext eq 'HASH') {
# seems to be a single row
$adrs->execute($url_ids[$currentUrlId], $jsontext->{'fmrp'}, $jsontext->'upa'}, $jsontext->'pda'}, $jsontext->'uid'}, $jsontext->'umrp'}, $jsontext->'ueid'});# || &die_clean("Couldn't execute\n$adsql\n".$db->errstr."\n" );
$adrs2->execute($url_ids[$currentUrlId]);
$currentUrlId++;
} elsif (ref $jsontext eq 'ARRAY') {
foreach my $row (#$jsontext){
$adrs->execute($url_ids[$currentUrlId], $row->{'fmrp'}, $row->{'upa'}, $row->{'pda'}, $row->{'uid'}, $row->{'umrp'}, $row->{'ueid'});# || &die_clean("Couldn't execute\n$adsql\n".$db->errstr."\n" );
$adrs2->execute($url_ids[$currentUrlId]);
$currentUrlId++;
}
}
I have an array
my #cols = ("accountid", "balance");
and a dataset
my $rowsref=$dbh->selectall_arrayref($_[0]);
foreach my $row (#$rowsref) {
print join(", ", map {defined $_ ? $_ : "(null)"} #$row), "\n";
}
which prints "1, 150".
I would like to get a JSON output like [{"accountid": 1, "balance": 150},{..}].
I have the JSON module loaded, but unsure how to merge #cols with each $row.
edit: added explanation of column name transaction in 2nd example
edit: Fixed for your requirement of a single JSON encoding of the whole resultset.
edit: forgot keys in cols mapping code in 2nd example.
edit: typo'd hashref everywhere to arrayref. :-
Firstly, use selectall_hashref instead, so that it already contains the key names.
Then use one of the JSON encoding modules to encode each row.
(making the same assumptions as your code....)
Using the list-of-hashrefs from selectall_hashref() as-is:
use JSON::XS;
use 5.10.0;
my $rowsref = $dbh->selectall_hashref($_[0]);
print JSON::XS::encode_json($rowsref),"\n";
Performing translation on colnames from selectall_hashref():
If the column names from the database aren't the same as your column names, then you'll need a mapping:
use JSON::XS;
use 5.10.0;
my $trans = { account => 'accountid', amount => 'balance' };
my $rowsref = $dbh->selectall_hashref($_[0]);
my $output = [];
for my $row (#$rowsref) {
push #$output, {
map {
my $colname = exists($trans->{$_}) ? $trans->{$_} : $_;
my $value = $row->{$_};
$colname => $value;
} keys %$row
});
}
print JSON::XS::encode_json($output),"\n";
For each $row above of the resultset, keys %$row gives back the column names in the row as returned from the database.
The map operation takes each of those column names and producues 2 scalar values; (1) $colname is either the original database column name or (if it's found in the $trans hashref) a 'translation' of the column name; (2) $value is the value returned by the database for this column name in this particular $row. $colname => $value returns both the $colname and $value from the map as a 'flattened' pair of scalar values. That means that the map operation returns a list of scalar values twice as long as the original list of column names returned by keys %$row.
Finally, the push #$output, { ... } creates an anonymous hash reference from that list of scalar values in key,value,key,value,... order and adds it to the end of the $output array reference.
Blind translation from selectall_arrayref()
If (for some reason) you have a pathological aversion to querying hashrefs from your database, I guess you could do:
use 5.10.0;
my #cols = ("accountid", "balance");
my $rowsref = $dbh->selectall_arrayref($_[0]);
my $output = [];
for my $row (#$rowsref) {
my %row = map { $cols[$_] => $row->[$_] } (0 .. $#cols);
push #$output, \%row;
}
print JSON::XS::encode_json($output),"\n";
That assumes there are only two columns coming back from the query, though.
"Defined or" operator:
By the way... assuming a late enough perl, you can replace this sort of thing:
defined $_ ? $_ : "(null)"
with this:
$_ // "(null)"
Your code editor (e.g: Vim) might not syntax highlight it correctly if it's not up to date with perl. (e.g: it might treat it as an m// construct).
Note that PostgreSQL can also generate JSON. If it is an option for you then Perl JSON module is redundant.
I expect this is a simple coding error.
When trying to get all results from database table, the first result is always missed off. Even when adding and removing information to the database it will always miss off the result with the lowest ID.
$data = mysql_query("SELECT * FROM tbl_messages")
or die(mysql_error());
$info = mysql_fetch_array( $data );
while($info = mysql_fetch_array( $data ))
{
Print "" .$info['subject']. "";
echo "<hr>";
}
Your current code calls mysql_fetch_array and assigns the result (the first row of the result set) to $info. You don't do anything with $info, and in the next line you overwrite it with another call to mysql_fetch_array.
You need to delete this line:
$info = mysql_fetch_array( $data );
From the php manual:
array mysql_fetch_array ( resource $result [, int $result_type = MYSQL_BOTH ] )
Returns an array that corresponds to the fetched row and moves the internal data pointer ahead.
So after
$data = mysql_query(...) you get an array $data and the internal data pointer points on the first element of $data.
The first call of mysql_fetch_array(...) moves the internal data point ahead, so it now points to the second element.
Then, your while-loop calls mysql_fetch_array(...) AGAIN before issuing the first Print, so the second element gets printed.
You can fix it by removing this line:
$info = mysql_fetch_array( $data );
Remove the first mysql_fetch_array statement.
something like
$data = mysql_query("SELECT * FROM tbl_messages")
or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
Print "" .$info['subject']. "";
echo "<hr>";
}
You are skipping the first entry by using the code as above.
From mysql_fetch_array
Returns an array that corresponds to the fetched row and moves the
internal data pointer ahead.
Which means that when you get to the while, you have already read the first row, but not used it yet.
I had problems like this too with my table query's ignoring row 0 (the first occurance) and now that I see this I finally understand what's going on.
The clarification is also understandable.
You are asking for a query_fetch_array and you put what it finds in $info. This seems ok. Next you ask for the remaining rows, since you just removed one row from the possible returns, it also works perfectly.
Remove this line:
$info = mysql_fetch_array( $data );
and you get all your rows from your table. Or, if you are wondering, ECHO the $info before your while loop in the fashion you are printing or just try var_dumping it.
App::import('model','User');
$user_model = new User();
$xxx = $user_model->find("all", array("fields"=>array("User.yyy")));
$zzz = $user_model->find("count", array("fields" => "User.yyy"));
$arr = array();
for($i=0; $i<=$zzz; $i++){
$rs = $xxx["i"]["User"]["yyy"];
array_push($arr , $rs);
}
print_r($arr);
I am using the above cakephp code to get $xxx as a mysql result set.
I need to store all the values corresponding to "yyy" field in the mysql table into an arrray.
I tried printing the result set and got output like this:-
print_r($zzz)= 1646 // prints the total number of results
print_r($xxx[0]["User"]["yyy"]) = abcde //the first element of the result set
After I run the code above, It just prints an empty array.
Can someone help me out here??
The problem is here:
$xxx["i"]["User"]["yyy"]
It should be:
$xxx[$i]["User"]["yyy"]
Assuming the code is located in a controller, I would write it like this:
$this->loadModel('User');
$arr = $this->User->find("list", array("fields"=>array("User.yyy")));
find("list") should return an array indexed by id
If you want to remove the ids, you can do this:
$arr = array_values($arr)