mongodb gathering all records from different collections - php

i am trying to grab all records from mongodb using php.
i have two collections. question is, in practice will i be able to make a simple sentence such as for each record on the database? :
ie: john[from names collection] lives in city[from city collection] who
drives[from car collection].
Is this the correct coding for the above? I am still a newbie trying to learn step by step
<?php foreach ($details as $doc) {
echo $doc['name'] . ' lives in'; }
foreach ($place as $city) {
echo $city['name'] . ' who drives a '; }
foreach ($car as $ride) {
echo $ride['name'];
echo '<br>'} ?>
your thoughts are welcome

I expect this to be used with, say, a user_id of sorts. Doing a full table scan of this would be a really bad idea.
Here is what you can do providing you have the user_id:
$users = $mongo->users->find(['_id' => ['$in' => [1,2,3,4,5,6,7,8,9]]]);
// Set some variables which will help us perform the detail queries
$cityIds = [];
$rideIds = [];
$userResults = [];
$cityResults = [];
$rideResults = [];
// Iterate through our users.
foreach($users as $_id => $user){
// We store the MongoId for use in queries
$cityIds[] = $user['city_id'];
$rideIds[] = $user['ride_id'];
// We then store the user result itself so we don't
// Do this query multiple times.
$userResults[$_id] = $user;
}
// Now, let's get our first details.
$cityResults = iterator_to_array(
$mongo->cities->find(['_id' => ['$in' => $cityIds]])
);
// And our ride details
$rideResults = iterator_to_array(
$mongo->rides->find(['_id' => ['$in' => $rideIds]])
);
// Now let's loop and echo
foreach($userResults as $k => $user){
echo $user['name'] .
' lives in ' .
$cityResults[$user['city_id']]['name'] .
' who drives a ' .
$rideResults[$user['ride_id']]['name'];
}
Something like that would do the trick.
Here I assume that your user schema has a city and ride ID in it respectively and that the two ID fields store an ObjectId (_id) of a city and ride row; this seems to be the most logical schema.

Nest the for loops inside of each other.
<?php
foreach ($details as $doc) {
foreach ($place as $city) {
foreach ($car as $ride) {
echo $doc['name'] . ' lives in '.$city['name'].' who drives a '.$ride['name'].'<br/>';
}
}
}
?>
Thats how i do it when im trying to access data in multiple collections to form the output

Related

Accessing results from collect() using neo4j-php-client

The below displays:
Marlena has 12 paintings (which is basically from the docs)
How do I access the data in collect(Paintings)
ex: title
$query = "MATCH (n:Artist)-[:PAINTED]->(Painting) RETURN n.first_name, collect(Painting) as paintings";
$result = $client->run($query);
foreach ($result->getRecords() as $record) {
echo sprintf('%s has %d paintings', $record->value('n.first_name'), count($record->value('paintings')));
echo '<br/>';
}
I would like to display:
Artist Name:
painting title
painting title
etc
I assume this data can be pull from either Painting or paintings. I am just unsure how to put together the query. It will display using print_r and the record so I know the data is coming through.
This should work for you:
$query = "MATCH (n:Artist)-[:PAINTED]->(Painting) RETURN n.first_name, collect(Painting) as paintings";
$result = $client->run($query);
foreach ($result->getRecords() as $record) {
echo sprintf('%s has %d paintings:<br/>', $record->value('n.first_name'), count($record->value('paintings')));
foreach ($record->value('n.paintings') as $painting) {
echo sprintf('- %s<br/>', $painting->value('title'));
}
echo '<br/>';
}
a) I suggest you alias your return values, it is easier to fetch them at the driver level
b) The paintings record value returns an array of Node objects, thus is iterable, no need to count for doing the for loop :
$query = "MATCH (n:Artist)-[:PAINTED]->(Painting) RETURN n.first_name as firstName, collect(Painting) as paintings";
$result = $client->run($query);
foreach($result->records() as $record) {
echo sprintf('%s painted %d paintings', $record->get('firstName'), count($record->get('paintings'))) . PHP_EOL;
foreach ($record->get('paintings') as $painting) {
echo sprintf('%s - %d views', $painting->value('title'), $painting->value('views')) . PHP_EOL;
}
}
I ended up getting it to work with the following:
foreach ($result->getRecords() as $record) {
$fname = $record->values()[0]->get('first_name');
$lname = $record->values()[0]->get('last_name');
echo '<strong>'.$fname.' '.$lname.' painted:</strong><br/>';
for ($x = 0; $x < count($record->values()[1]); $x++) {
print_r($record->values()[1][$x]->get('title'));
echo ' - ';
print_r($record->values()[1][$x]->get('views'));
echo ' views<br/>';
}
echo '<br/>';
}
Which provides the following output:
First Name Last Name painted:
Lumine - 86 views
Pooled Water - 69 views
Still Lake - 125 views
Final Notes
I actually tried code similar to what you suggested during my struggle to get this working. I'm a bit confused why it does not.
So I'm left wondering. Is what I come up with acceptable?

Function Errors in PHP Script

I've been wrestling with a really cool script someone gave me, trying to adapt it to my site. I'm getting closer, but I'm still getting two errors that have me puzzled.
First: Warning: Invalid argument supplied for foreach()...
This is the foreach statement:
foreach ($Topic as $Topics)
It follows a function:
function generate_menu_items($PopTax, $Topics, $Current_Topic)
I THINK the problem relates to the middle value in the function - $Topics. I don't understand how it's derived. My guess is it's supposed to be an array of all the possible topics (represented by $MyTopic in my database). But I'm not that familiar with functions, and I don't understand why he put the function and foreach BEFORE the database queries. (However, there is a more general DB query that establishes some of these values higher up the food chain.)
Here's the second problem: Fatal error: Call to undefined function render_menu()...
Can anyone tell me how and where I should define this function?
Let me briefly explain what this script is all about. First imagine these URL's:
MySite/topics/animal
MySite/topics/animal-homes
MySite/topics/animal-ecology
MySite/topics/mammal-ecology
MySite/topics/bird-ecology
Two key values are associated with each URL - $PopTax (popular name) and $MyTopic. For the first three URL's, $PopTax = Animal, while the other two are Mammal and Bird. $MyTopic = Ecology for the last three rows. For the first two, $MyTopics = Introduction and Homes.
The ID's for both values (Tax_ID and Topic_ID) are simply the first three letters of the name (e.g. Mam = Mammal, Eco = Ecology). Also, Life is the Parent of Animal, which is the Parent of Vertebrate, which is the Parent of Mammal.
Now I'm just trying to pull it all together to create a little index in the sidebar. So if you visit MySite/topics/animal-ecology, you'd see a list of ALL the animal topics in the sidebar...
Animals
Animal Classification
Animal Homes
Animal Ecology
As you can see there are some case and plural differences (animal vs Animals), though I don't think that really relates to the problems I'm having right no.
But I'm not sure if my code just needs to be tweaked or if there's something grotesquely wrong with it. Something doesn't look right to me. Thanks for any tips.
$Tax_ID = 'Mam'; // Mam represents Mammal
$Current_Topic = 'Homes';
function generate_menu_items($PopTax, $Topics, $Current_Topic)
{
$menu_items = array();
foreach ($Topic as $Topics)
{
$url = "/topics/$PopTax[PopTax]-$Topic[MyTopic]";
$title = "$PopTax[PopTax] $Topic[MyTopic]";
$text = $Topic['MyTopic'];
if ($Topic === 'People') {
$url = "$PopTax[PopTax]-and-$Topic[MyTopic]";
$title = "$PopTax[PopTax] and $Topic[MyTopic]";
$text = "$PopTax[PopTax] & $Topic[MyTopic]";
}
if ($Topic === 'Movement' && $PopTax['Parent'] == 'Ver' && $PopTax['PopTax'] != 'Human') {
$url = "$PopTax[PopTax]-locomotion";
$title = "$PopTax[PopTax] Locomotion";
$text = "Locomotion";
}
$menu_items[] = array(
'url' => strtolower($url),
'title' => ucwords($title),
'text' => ucfirst($text),
'active' => ($Topic['MyTopic'] === $Current_Topic)
);
}
return $menu_items;
}
function generate_menu_html($menu_items)
{
$list_items = array();
foreach ($menu_items as $item)
{
if ($item['active']) {
$list_items[] = "<li><span class=\"active\">$item[text]</b></span></li>";
} else {
$list_items[] = "<li>$item[text]</li>";
}
}
return '<ol>' . implode("\n", $list_items) . '</ol>';
}
$stm = $pdo->prepare("SELECT T.Topic_ID, T.MyTopic
FROM gz_topics T
JOIN gz_topics_poptax TP ON TP.Topic_ID = T.Topic_ID
WHERE TP.Tax_ID = :Tax_ID");
$stm->execute(array('Tax_ID' => $Tax_ID));
// Fetch all rows (topics) as an associative array
$Topics = $stm->fetchAll(PDO::FETCH_ASSOC);
// Get the DB row for the taxon we're dealing with
$stm = $pdo->prepare("SELECT Tax.ID, Tax.PopTax, Tax.Parent
FROM gz_poptax Tax
WHERE Tax.ID = :Tax_ID");
$stm->execute(array('Tax_ID' => $Tax_ID));
// Fetch a single row, as the query should only return one row anyway
$PopTax = $stm->fetch(PDO::FETCH_ASSOC);
// Call our custom functions to generate the menu items, and render them as a HTML list
$menu_items = generate_menu_items($PopTax, $Topics, $Current_Topic);
$menu_html = render_menu($menu_items);
// Output the list to screen
echo $menu_html;
You want foreach ($Topics as $Topic). You are looping over each $Topic in $Topics is another way to think of it.

(PHP+MySQL) How can I echo the column name on a specific condition?

I am using PHP 5.4 with a MySQL database.
This database represents a media library. The table I'm dealing with has one column, "Title", with obvious contents, and then a series of boolean columns, representing the availability of that title on a given platform. So a row looks like
TITLE: "Curb Your Enthusiasm: The Game"
PS4: 0
Atari 2600: 1
Dreamcast: 0
And so on.
The PHP code I would like to write be, in pseudocode,
Echo row[0] (title)
Cycle through other cells in the row
If the cell is '0' or NULL, do nothing
But if the cell is '1', echo the name of that column
So the result would be the echoing of
Curb Your Enthusiasm: The Game (Atari 2600, WonderSwan, Saturn)
It's the fourth statement that I can't quite work out. It seems to require the function mysqli_fetch_field, but I'm not sure of the syntax, and nothing I try after googling quite works.
I'd really appreciate any advice or examples someone could offer!
$database = mysqli_connect(SERVER,USERNAME,PASSWORD,'games');
$query = mysqli_query($database,"SELECT * FROM games` WHERE NAME LIKE '%ZELDA%'");
while ($row = mysqli_fetch_row($query)) {
echo $row[0]; // Echo title
for ($i=0;$i<sizeof($row);$i++) {
if ($row[$i] === '1') {
// ???????
}
}
}
Here is some rough untested code that should hopefully get you going.
while ($row = mysqli_fetch_assoc($query)) {
$columns = array(); // this will track the additional columns we need to display
foreach($row AS $column => $value) {
if($column == "title") {
echo $value; // this is the title, just spit it out
continue;
}
if($value == 1) {
// We have a column to display!
$columns[] = $column;
}
}
if(count($columns)) {
// We have one or more column names to display
echo " (" . implode(", ",$columns) . ")";
}
}
Some things to point out:
Using mysqli_fetch_assoc will allow you access to column names along with the values, which is useful here.
Keep track of the columns you want to display in an array first, this makes it easier at the end of each loop to format the output.
Sounds like you can do something like this:
// Simulates DB fetch
$titles = array(
array(
'TITLE'=>'Curb Your Enthusiasm: The Game',
'PS4'=>0,
'Atari 2600'=>1,
'Dreamcast'=>0
),
array(
'TITLE'=>'Curb Your Enthusiasm: The Book',
'PS4'=>1,
'Atari 2600'=>1,
'Dreamcast'=>0
)
);
foreach($titles as $title){
// get supported platforms
$supportedPlatforms = array();
foreach($title as $titleAttribute=>$titleValue){
if($titleAttribute != 'TITLE' && $titleValue == 1)
$supportedPlatforms[] = $titleAttribute;
}
echo $title['TITLE'] . ' (' . implode(', ', $supportedPlatforms) . ')' . "<br>";
}
Try running it here: http://phpfiddle.org/lite/code/pr6-fwt

Looping through database to get details, then send email with said values

I am bringing in brochures selected by visitors, and they can select multiple brochures. After three days they are meant to get an email reminding them of the brochures they have chosen.
Here is what I have so far:
$time_query = "SELECT * FROM users WHERE time < (now() - INTERVAL 1 minute)"; //" //GROUP BY time does group them into an array... well.. it doesnt display duplicate timestamps, so assume it saves it to an array'";
$time_query_result = mysql_query($time_query, $db) or
die("Could not execute sql: $time_query");
$users = array();
while($row = mysql_fetch_array($time_query_result)) {
if (!array_key_exists($users[$row["id"]], $users)) {
$users[$row["id"]] = array('email' => $row["email"], 'brochures' => array());
$users[$row["id"]]["brochures"] = array('b' => $row["brochures"], 't' => $row["time"]);
}
}
foreach ($users as $user) {
$text = '<html><body><p>Brochure reminder</p>';
$i = 0;
foreach ($user["brochures"] as $brochure) {
$text .= 'Brochures:<br />'.$i++ . $row["b"];
}
$text .= '</body></html>';
mail($user["email"], $subject, $text, $headers);
}
I am getting numbers through the emails instead of brochure names, and I think its something to do with the array_key_exists fuinction.
Each time a user selects a brochure, it creates its own row in the DB, and the idea was to pull in the multiple brochures a user selected at a time (by the time column), as many users can select brochures over a time period.
Any help would be appreciated :)
In your 'while' loop, you're creating a new 'brochures' element in your 'users' array, when I think you're wanting to append to it.
if (!array_key_exists($row["id"], $users)) {
$users[$row["id"]] = array('email' => $row["email"], 'brochures' => array());
}
$users[$row["id"]]["brochures"][] = array('b' => $row["brochures"], 't' => $row["time"]);
then in your 'foreach', you will want to use the brochure variable:
foreach ($user["brochures"] as $brochure) {
$text .= 'Brochures:<br />'.$i++ . $brochure["b"];
}
Your current code builds an array of users containing another array with the index 'brochures'. This array will always contain tow values.
{
'b' => $row["brochures"]
't' => $row["time"])
}
Regarding this fact the following statements doesn't make sense:
foreach ($user["brochures"] as $brochure) {
}
All you do is iterate over the two values with the index 'b' and 't'. If you want to iterate over a collection of brochures you need to adapt your code.
On the other hand you have a few important mistakes:
foreach ($user["brochures"] as $brochure) {
$text .= 'Brochures:<br />'.$i++ . $row["b"];
}
Why use a foreach if you don't even use the $brochure variable?
$text .= 'Brochures:<br />'.$i++ . $row["b"];
$row contains the last row, which is definitively not what you wanted. In fact, $row is out of scope, in a serious programming language you would see this.
$row["id"]
You use this about three times. So why not store it in a variable $id? Accessing arrays with indexes is a more expensive operation than simply accessing a variable.
In general I strongly encourage you to switch to an object oriented approach so you get rid of these ugly array in array in array solution...

Displaying multidimensional array in php

I have an array like this:
$tset = "MAIN_TEST_SET";
$gettc = "101";
$getbid = "b12";
$getresultsid = "4587879";
$users["$tset"] = array(
"testcase"=>"$gettc",
"buildid"=>"$getbid",
"resultsid"=>"$getresultsid"
);
Arrays in PHP is confusing me.
I want to display some like this:
MAIN_TEST_SET
101 b12 4587879
102 b13 4546464
103 b14 5545465
MAIN_TEST_SET3
201 n12 45454464
MAIN_TEST_SET4
302 k32 36545445
How to display this?
Thanks.
print_r($users)
That will print your array out recursively in an intuitive way. See the manual: http://us2.php.net/manual/en/function.print-r.php
If you want to print it in the specific way you formatted it above you're going to have to write a custom function that uses foreach looping syntax like this:
<?php
echo "<table>";
foreach($users as $testSetName=>$arrayOfTestCases){
echo "<tr><td>".$testSetName."</td></tr>";
foreach($arrayOfTestCases as $k=>$arrayOfTestCaseFields){
//$arrayOfTestCaseFields should be an array of test case data associated with $testSetName
$i = 0;
foreach($arrayOfTestCaseFields as $fieldName => $fieldValue){
//$fieldValue is a field of a testcase $arrayOfTestCaseFields
if($i == 0){
//inject a blank table cell at the beginning of each test case row.
echo "<tr><td> </td>";
$i++;
}
echo "<td>".$fieldValue."</td>";
}
echo "</tr>";
}
}
echo "</table>";
?>
Your data should be composed as follows:
$tset = "MAIN_TEST_SET";
$gettc = "101";
$getbid = "b12";
$getresultsid = "4587879";
$users[$tset] = array();
$users[$tset][] = array( "testcase"=>"$gettc",
"buildid"=>"$getbid",
"resultsid"=>"$getresultsid"
);
$users[$tset][] = ... and so forth ...
To fix the data structure you present (as Victor Nicollet mentions in his comment) you need something like this:
$users = array(); // Create an empty array for the users? (Maybe testsets is a better name?)
$testset = array(); // Create an empty array for the first testset
// Add the test details to the testset (array_push adds an item (an array containing the results in this case) to the end of the array)
array_push($testset, array("testcase"=>"101", "buildid"=>"b12", "resultsid" => "4587879"));
array_push($testset, array("testcase"=>"102", "buildid"=>"b13", "resultsid" => "4546464"));
// etc
// Add the testset array to the users array with a named key
$users['MAIN_TEST_SET'] = $testset;
// Repeat for the other testsets
$testset = array(); // Create an empty array for the second testset
// etc
Of course there are much more methods of creating your data structure, but this one seems/looks the most clear I can think of.
Use something like this to create a HTML table using the data structure described above.
echo "<table>\n";
foreach($users as $tsetname => $tset)
{
echo '<tr><td colspan="3">'.$tsetname.'</td></tr>\n';
foreach($tset as $test)
echo "<tr><td>".$test['testcase']."</td><td>".$test['buildid']."</td><td>".$test['resultsid']."</td></tr>\n";
}
echo "</table>\n";
The first foreach iterates over your test sets and the second one iterates over the tests in a test set.
For a short uncustomisable output, you can use:
print_r($users)
alternatively, you can use nested loops.
foreach($users as $key => $user) {
echo $key . "<br />"
echo $user["testcase"] . " " . $user["buildid"] . " " . $user["resultsid"];
}
If you are not outputting to html, replace the <br /> with "\n"

Categories