Mongodb replacing values 2 arrays deep in PHP - php

I have an Mongo Collection that looks like this
{
"_id": ObjectId("0000000000000123"),
"user_id": NumberLong(000010),
"location": {
"addresses": [{
"number": NumberLong(4410),
"street": "Test Drive",
"county": "New York County",
"city": "New York",
"state": "NY",
"zip": "00001",
"links": [{
"image": "http://www.google.com/test",
"datetime": " 11/24/1952"
}, {
"image": "http://www.google.com/test2",
"datetime": " 11/24/1990"
}
]
}
]
}
}
I need to be able to search for the links array for documents with www.google.com and be able to change it to www.yahoo.com
I tried a few versions of mongo's update but no success
$search_string = new MongoRegex("/www.google.com/i");
$collection->update(
array('location.addresses.links.image' => $search_string),
array('$set' => array('location.addresses.$.links.$.image' => '')),
array("multiple" => true)
);

So after more digging I found that the update position operator ($) can only be used one level deep.
So I decided to use foreach statements by reference to get what i needed done
$collection = new MongoCollection($this->db, 'users');
$search_string = new MongoRegex("/www.google.com/i");
$cursor = $collection->find(array('location.addresses.links.image' => $search_string));
foreach ($cursor as $doc)
{
foreach ($doc['location']['addresses'] as &$address)
{
foreach($address['links'] as &$link)
{
$link['image'] = str_replace('www.google.com', 'www.yahoo.com', $offender['image']);
}
}
$collection->update(array("_id" => $doc['_id']), $doc);
}

Related

PHP. change value in Array of Arrays not working

very weird issue: I try to change a json string using json_encode and json_decode. I converted the json string to an array(actually it's array of arrays) and try to change some data in it. but I couldn't get the data changed in inner array somehow.
$jsondata = ' {
"Id": "0400006",
"LastName": "Lincoln",
"FirstName": "Abraham",
"PreferredName": "Mr. Abraham Lincoln",
"BirthDate": "1992-06-20T00:00:00",
"PreferredEmailAddress": null,
"Addresses": [
{
"AddressId": "297143",
"Type": "Home",
"AddressLines": [
"201 S Grant Ave"
],
"AddressModifier": "",
"City": "Columbus",
"State": "OH",
"PostalCode": "43215",
"County": "049",
"Country": "",
"RouteCode": "",
"PhoneNumbers": [
{
"Number": "614-555-6666",
"Extension": "",
"TypeCode": "HOME"
}
],
"AddressLabel": [
"201 S Grant Ave",
"Columbus, OH 43215"
],
"PersonId": "0400006",
"EffectiveStartDate": "2008-06-13T00:00:00",
"EffectiveEndDate": null,
"IsPreferredAddress": true,
"IsPreferredResidence": true,
"TypeCode": "H",
"CountryCode": ""
},
{
"AddressId": "727032",
"Type": "Web Address",
"AddressLines": [
"285 E. Main Ave",
"Apt B"
],
"AddressModifier": "",
"City": "Columbus",
"State": "OH",
"PostalCode": "43215",
"County": "049",
"Country": "",
"RouteCode": "",
"PhoneNumbers": [
{
"Number": "614-555-6666",
"Extension": "",
"TypeCode": "HOME"
}
],
"AddressLabel": [
"285 E. Main Ave",
"Apt B",
"Columbus, OH 43215"
],
"PersonId": "0400006",
"EffectiveStartDate": "2018-06-25T00:00:00",
"EffectiveEndDate": null,
"IsPreferredAddress": false,
"IsPreferredResidence": false,
"TypeCode": "WEB",
"CountryCode": ""
}
],
"EmailAddresses": [],
"Phones": [
{
"Number": "614-555-6666",
"Extension": "",
"TypeCode": "HOME"
}
],
"AddressConfirmationDateTime": null,
"EmailAddressConfirmationDateTime": null,
"PhoneConfirmationDateTime": null,
"LastChangedDateTime": "2018-06-27T20:42:22Z",
"ChosenFirstName": "",
"ChosenMiddleName": "",
"ChosenLastName": "",
"PersonalPronounCode": "",
"IsDeceased": false
}
';
$newAddressData = [
"address1" => "5857 Newbridge Dr.",
"address2" => "Apt D",
"city" => "Chicago",
"state" => "Illions",
"postalcode" => "23456"
];
public function modifyData($jsonStr, $newAddressData){
$personInfoData = json_decode($jsonStr, true);
$addressArray = $personInfoData['Addresses'];
$webAddressObj = null;
foreach($addressArray as $address){
if($address['Type'] == 'Web Address' ){
$webAddressObj = &$address;
break;
}
}
if($webAddressObj != null){
echo("update it!");
$webAddressObj['AddressId'] ='';
$webAddressObj['PhoneNumbers']=[];
$webAddressObj['AddressLabel'] =[];
$webAddressObj['AddressLines'] =[$newAddressData['address1'], $newAddressData['address2']];
$webAddressObj['EffectiveStartDate']='';//2018-06-25T00:00:00
$webAddressObj['City']=$newAddressData['city'];
$webAddressObj['State']=$newAddressData['state'];
$webAddressObj['PostalCode']=$newAddressData['postalcode'];
}else{
echo("new address");
$newAddress = new AddressInfo();
$newAddress->Type = "Web Address";
$newAddress->TypeCode = "WEB";
$newAddress->AddressLines =[$newAddressData['address1'], $newAddressData['address2']];
$newAddress->EffectiveStartDate ='';
$newAddress->City = $newAddressData['city'];
$newAddress->State=$newAddressData['state'];
$newAddress->PostalCode=$newAddressData['postalcode'];
$newAddressJson = json_encode($newAddress);
$addressArray[] = $newAddressJson;
}
print_r($webAddressObj);
echo "<p>";
print_r($addressArray);
echo "<p>";
return $personInfoData;
}
$personalInfoData = modifyData($jsondata, $newAddressData);
echo json_encode($personalInfoData);
========================================
You'll find out the $personalInfoData didn't get changed.
This: $webAddressObj = &$address; does not create a reference to that element of the original array. It creates a reference to the temporary copy of the element created by foreach. The reference to that copy does stay set after you've broken out of the loop, but making changes to it will not affect the original array.
If you want a reference to the original element, You'll also need to assign $addressArray by reference to begin with.
$addressArray = &$personInfoData['Addresses'];
you'll need to maintain the reference in the foreach loop, like
foreach($addressArray as &$address){
And you'll still need to assign by reference inside the loop as you're currently doing.
$webAddressObj = &$address;
Rather than keeping track of all the references, it may be easier to follow if you refer directly to the original array by key instead.
$webAddressKey = null;
foreach($addressArray as $key => $address){
if($address['Type'] == 'Web Address' ){
$webAddressKey = $key;
break;
}
}
if($webAddressKey != null){
echo("update it!");
$personInfoData['Addresses'][$webAddressKey]['AddressId'] ='';
...
}

Nested JSON Object with array in PHP

I want JSON object as follows in that personal, address and itm have sequence of json object.
{
"id": "1",
"state": "12",
"personal": [
{
"name": "abc",
"contact":"1111111"
"address": [
{
"line1": "abc",
"city": "abc",
"itm": [
{
"num": 1,
"itm_detatils": {
"itemname": "bag",
"rate": 1000,
"discount": 0,
}
}
],
"status": "Y"
}
]
}
]
}
But I am getting result as follows in that I want json array at address and itm_details.
{
"id": "1",
"state": "12",
"personal": [
{
"name": "abc",
"contact": "1111111",
"address": {
"line1": "abc",
"city": "abc",
"itm": {
"inum": "1",
"itm_detatils": {
"itemname": "bag",
"rate": 1000,
"discount": 0
}
},
"status": "Y"
}
}
]
}
My PHP Code is as follow:
In that I am creating simple array and after that array inside array but during encoding to json it's not showing sequence of json object.
$a=array();
$a["id"]="1";
$a["state"]="12";
$a["personal"]=array();
$a["personal"][]=array(
"name"=>"abc",
"contact"=>"1111111",
"address"=>array(
"line1"=>"abc",
"city"=>"abc",
"itm"=>array(
"inum"=>"1",
"itm_detatils"=>array(
"itemname"=>"bag",
"rate"=>1000,
"discount"=>0,
),
),
"status"=>"Y",
),
);
echo json_encode($a);
Thanks in advance.
Add one more array
//...
"address" => array(
array(
"line1"=>"abc",
"city"=>"abc",
// ...
),
)

PHP getting values from nested json

I have this json listed below. I was using json_decode to get some of the values. Such as getting the id value:
$decoded_array = json_decode($result, true);
foreach($decoded_array['issue'] as $issues ){
$value[] = $issues["id"];
This method is working for getting the id value, however, I want to get the emailAddress values for both Bob and John. I believe you can get a single value by doing this:
$value[] = $issues["fields"][people][0][emailAddress];
Is it possible to get both email addresses in an efficient manner?
Edited --------
How would you get data with an expanded dataset? Example:
{
"startAt": 0,
"issue": [
{
"id": "51526",
"fields": {
"people": [
{
"name": "bob",
"emailAddress": "bob#gmail.com",
"displayName": "Bob Smith",
},
{
"name": "john",
"emailAddress": "john#gmail.com",
"displayName": "John Smith",
}
],
"skill": {
"name": "artist",
"id": "1"
}
}
},
{
"id": "2005",
"fields": {
"people": [
{
"name": "jake",
"emailAddress": "jake#gmail.com",
"displayName": "Jake Smith",
},
{
"name": "frank",
"emailAddress": "frank#gmail.com",
"displayName": "Frank Smith",
}
],
"skill": {
"name": "writer",
"id": "2"
}
}
}
]
}
I only want to extract the email addresses from both "fields". Is there an easy way to loop through all the "fields" to get "emailAddress" data?
You need to delve deeper into the array.
foreach ($decoded_array['issue'][0]['fields']['people'] as $person) {
echo $person['emailAddress'];
}

PHP JSON add array

i need some assistance with properly generating JSON. I almost have it, but I need to have each category and its related item in its own array. I have multiple categories each with many items under them. My JSON looks good, i just need the categories as an array along with its items. Any help is greatly appreciated!
Here is my code:
$channel ['items']['post']['categories'][$category_name]['details'][] = array(
'title' => $title,
'price' => $price,
'date_time' => $date_time,
'description' => $description,
);
}
$channels = array($channel);
$json = json_encode($channel);
header('Content-type: application/json');
echo $json;
My JSON looks like this currently:
{
"items": { /// THIS IS MEANT TO ORGANIZE UNDER ITEMS
"post": { ///THIS IS PROBABLY UNNECESSARY, I JUST HAVEN'T REMOVED IT.
"categories": {
"Baby": { ///I HAVE MANY MANY CATEGORIES
"details": [ ///I HAVE MANY MANY ITEMS UNDER EACH CATEGORY
{
"title": "trying with category id again",
"price": "3344.55",
"date_time": "2013-11-11 17:33:49",
"description": "Descriptor sb ",
"category_id": "3",
},
]
But I want it to look like this:
{
"items": {
"categories": [{ /// NEED THE BRACKET HERE
"Baby": {
"details": [
{
"title": "trying with category id again",
"price": "3344.55",
"date_time": "2013-11-11 17:33:49",
"description": "Descriptor sb ",
},
{
"title": "what the",
"price": "44444.66",
"date_time": "2013-11-18 20:15:58",
"description": "Blah blah",
},
]
},
"Baby Stuff": {
"details": [
{
"title": "putting in title",
"price": "3000.99",
"date_time": "2013-11-11 17:42:15",
"description": "Blah blah blah",
},
{
"title": "adding another listing",
"price": "400000.99",
"date_time": "2013-11-17 22:37:02",
"description": "Blah blah blah",
},
]
},
"More Baby Stuff": {
"details": [
{
"title": "does this work",
"price": "4000.77",
"date_time": "2013-11-18 19:59:49",
"description": "Description ",
},
{
Add another [] after ['categories'] and that should do the trick
$channel ['items']['post']['categories'][][$category_name]['details'][] = array( // ...
$channel ['items']['post']['categories'][]['Baby']['details'][] = array(
'title' => 'trying with category id again',
'price' => 3344.55,
'date_time' => '2013-11-11 17:33:49',
'description' => 'Descriptor sb',
);
$channels = array($channel);
$json = json_encode($channel);
echo $json;
Output
{
"items": {
"post": {
"categories": [
{
"Baby": {
"details": [
{
"title": "trying with category id again",
"price": 3344.55,
"date_time": "2013-11-11 17:33:49",
"description": "Descriptor sb"
}
]
}
}
]
}
}
}
See it working here on ideone
Based on comments and edits to OP, perhaps you should be looking at a data structure like this:
{
"categories":
[
{
"category_name": "Baby",
... [Other category metadata],
"category_items":
[
{
"item_name": "Item Name",
... [Other item information]
},
{ [next item] },
...
]
},
{ [ next category ] },
...
]
}
This means one might build this object in similar manner to the following (assuming for example you are building this from DB query):
$channel = new stdClass();
$channel->categories = array();
LOOP for categories as $category
$category = new stdClass();
$category->category_name = 'some value';
$category->some_other_category_metadata = 'some other value';
$category->category_items = array();
INNER LOOP on items in category as $item
$item = new stdClass();
$item->item_name = 'item name';
$item->some_other_item_data = 'data';
$category->category_items[] = $item;
END INNER LOOP
$channel->categories[] = $category;
END OUTER LOOP
json_encode($channel);

How to create array of nested comments out of flat array from DB

After querying the DB for comments that are nested in a closure table, like Bill Karwin suggests here What is the most efficient/elegant way to parse a flat table into a tree?, I now get the following datastructure from SQL:
"comments": [
{
"id": "1",
"breadcrumbs": "1",
"body": "Bell pepper melon mung."
},
{
"id": "2",
"breadcrumbs": "1,2",
"body": "Pea sprouts green bean."
},
{
"id": "3",
"breadcrumbs": "1,3",
"body": "Komatsuna plantain spinach sorrel."
},
{
"id": "4",
"breadcrumbs": "1,2,4",
"body": "Rock melon grape parsnip."
},
{
"id": "5",
"breadcrumbs": "5",
"body": "Ricebean spring onion grape."
},
{
"id": "6",
"breadcrumbs": "5,6",
"body": "Chestnut kohlrabi parsnip daikon."
}
]
Using PHP I would like to restructure this dataset, so the comments are nested like this:
"comments": [
{
"id": "1",
"breadcrumbs": "1",
"body": "Bell pepper melon mung."
"comments": [
{
"id": "2",
"breadcrumbs": "1,2",
"body": "Pea sprouts green bean."
"comments": [
{
"id": "4",
"breadcrumbs": "1,2,4",
"body": "Rock melon grape parsnip."
}
]
},
{
"id": "3",
"breadcrumbs": "1,3",
"body": "Komatsuna plantain spinach sorrel."
}
]
},
{
"id": "5",
"breadcrumbs": "5",
"body": "Ricebean spring onion grape."
"comments": [
{
"id": "6",
"breadcrumbs": "5,6",
"body": "Chestnut kohlrabi parsnip daikon."
}
]
}
]
I have hacked together a solution, but it seems over complex, and I have a feeling that there is some clever solution out there to do this in an elegant and efficient way, but I dont know how?
Assuming you fetch all your data into an array indexed by the "id":
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$nodes[$row["id"]] = $row;
}
I tested the following and it works to produce the JSON output you want:
foreach ($nodes as &$node) {
$parent = array_shift(array_slice(explode(",",$node["breadcrumbs"]), -2, 1));
if ($parent == $node["id"]) {
$forest["comments"][] = &$node;
} else {
$nodes[$parent]["comments"][] = &$node;
}
}
print json_encode($forest, JSON_PRETTY_PRINT);
I would suggest a 2 stage approach.
Stage 1 : Build an nested array
Stage 2 : Convert array to JSON
Stage 1 can be handled simply by creating your elements based on your breadcrumbs.
For example, for "breadcrumbs": "1,2,4"
$comments_array[1][2][4] = $current_element_from_flat_array;
I'm not sure what the most elegant way to get to the above code is, perhaps by parsing the breadcrumbs into its element and having if-else statements based in this. It might be functional, but It's probably not the most elegant code.
$breadcrumbs_list = explode(",", $pizza);
if (count($breadcrumbs_list) == 2)
$comments_array[$breadcrumbs_list[1]][$breadcrumbs_list[2]] = $current_element_from_flat_array;
else if (count($breadcrumbs_list) == 3)
$comments_array[$breadcrumbs_list[1]][$breadcrumbs_list[2]][$breadcrumbs_list[1]] = $current_element_from_flat_array;
Stage 2 can be done using json_encode() provided by PHP.
$tree = array('NULL' => array('children' => array()));
foreach($array as $item){
if(isset($tree[$item['id']])){
$tree[$item['id']] = array_merge($tree[$item['id']],$item);
} else {
$tree[$item['id']] = $item;
}
$parentid = is_null($item['id_parent']) ? 'NULL' : $item['id_parent'];
if(!isset($tree[$parentid])) $tree[$parentid] = array('children' => array());
//this & is where the magic happens: any alteration to $tree[$item['id']
// will reflect in the item $tree[$parentid]['children'] as they are the same
// variable. For instance, adding a child to $tree[$item['id']]['children]
// will be seen in
// $tree[$parentid]['children'][<whatever index $item['id'] has>]['children]
$tree[$parentid]['children'][] = &$tree[$item['id']];
}
$result = $tree['NULL']['children'];
//always unset references
unset($tree);
This solution needs a little polishing. Hope it helps.

Categories