update an embedded document in mongodb using php - php

I am making a blogging site so I am using MongoDB as my DB. In my collection "articles", I have 1 embedded doc named posts and I want to insert 1 more embedded doc. comments into it.
DB:
{
"_id": ObjectId("4f41a5c7c32810e404000000"),
"username":"abc",
"posts": [
{
"_id": 1,
"content": "dskcnkdcnksldcnskcd",
"title" : "test1"
},
{"_id": 2,
"content": "dskcsdsl;d,cl;sdcl;sdmcnkdcnksldcnskcd",
"title" : "test2"
},
]
}
I want to insert comments into posts.
{
"_id": ObjectId("4f41a5c7c32810e404000000"),
"username":"abc",
"posts": [
{
"_id": 1,
"content": "dskcnkdcnksldcnskcd",
"title" : "test1",
"comments":[
{
"content": "usdhcjsdcjskd",
"by" : "abc"
}
]
},
{"_id": 2,
"content": "dskcsdsl;d,cl;sdcl;sdmcnkdcnksldcnskcd",
"title" : "test2"
}
]
}

Comments is actually an embedded document of posts in your document as such you need to change your query a little to:
$collection->update(array('_id' => new MongoId($bid),'posts.id'=> $pid),array('$push' => array('posts.$.comments' => $comment)));
Try that.
Notice how I have used the positional operator? You can read more about it here: http://www.mongodb.org/display/DOCS/Updating/#Updating-The%24positionaloperator

the thing you need to be careful is your structure for first insert. For example you have some user with some lists and you want to let him to have up to 5 lists. This is how you can do it with PHP:
You need to install your mongodb extension if you do not have it in your PHP environment on your localhost server
You need to install mongodb and run it.
After all that is done you can easily do it like this:
$m = new Mongo("mongodb://localhost");
$db = $m->statistic->list;
// statistic is my database and list are collection.
$list =
array(
'_id' => 18,
'lists' =>
array(
array(
'name' => 'Magento and PHP developer',
'recipients' =>
array(
'name' => 'Kristijan Glibo',
'email' => 'glibo.kristijan#gmail.com'
),
'count' => 12345),
));
You can see here that I use some (int)18 for my _id. If you do not specify it, Mongo will generate it. I use it like this just for testing purposes. Notice here that lists are array and every list inside it are array too with their own data! My list Magento and PHP developer have data about recipients and count. Recipients also have some unique data.
Lets make first insert into our Mongodb:
$document = $db->insert($list);
If we now dump collection to check out what we saved inside of it we will get this:
NOTE: To get your collection and everything inside it you can use this code:
$documents = $db->find();
echo '<pre>';
foreach ($documents as $doc) {
var_dump($doc);
}die();
********************this is dumped data*******************
["_id"]=>
int(18)
["lists"]=>
array(3) {
[0]=>
array(3) {
["name"]=>
string(10) "Magento and PHP developer"
["recipients"]=>
array(2) {
["name"]=>
string(4) "Kristijan Glibo"
["email"]=>
string(25) "glibo.kristijan#gmail.com"
}
["count"]=>
int(12345)
}
Lets now update our user and add him more lists:
$updatelist = array('name' => 'updatelist', 'recipients' => array(),'count'=>2876);
$documentupdate = $db->
update(
array('_id'=>18),
array('$addToSet' => array('lists'=> $updatelist)));
You are telling him which object to update by selectin _id => 18 and how to update. I test this and it will add new list if that list do not exist. If exist it will skip it.
Hope this helps!

Related

Merge Data from multiple API Endpoints into one Database

I am currently building a table that stores data it receives from an api endpoint via url. I want to add additional columns from a different endpoint. The Data is stored in JSON format and the two datasets have one key in common that is the item name.
I cant think of a way to merge these two datasets by their related key. I just started coding like a month ago. Do I need to build a database that stores the data or can i do it with php? I expirimented with mySQL but i couldent find a way to load the data from the url into my database.
Thank you very much for your help!
So i pretent to have the following data in base.json
[{ "id": 4, "name": "james" }, { "id": 6, "name": "tim" }]
and in 2nd.json
{ "4": ["flower", "car"], "6": ["house", "server"] }
so now the following PHP-Code will merge them
<?php
$api_endpoint = json_decode(file_get_contents('base.json'), true);
$additional = json_decode(file_get_contents('2nd.json'), true);
$merged_data = array();
foreach ($api_endpoint as $data) {
$merged_data[] = array_merge($data, $additional[$data['id']]);
}
var_dump($merged_data);
The Result would look like this:
["0"] => Array(
["id"] => int(4)
["name"] => str("james")
["0"] => str("flower")
["1"] => str("car")
)
["1"] => Array(
["id"] => int(6)
["name"] => str("tim")
["0"] => str("house")
["1"] => str("server")
)
So now you could use the $merged_data and insert it into your database.

Correctly format JSON file

I'm trying to create a JSON file which contains objects and an array. Yet I'm missing the [ ]-brackets. I don't really know the exact terms for these JSON parts, which makes finding a solution using Google incredibly hard. I'm also a fairly new PHP coder, so I'm still learning. Any help or tips are really appreciated!
Code to create the JSON file:
$db_export = [
'account' => [
'username' => $username,
'email' => $email
]
];
file_put_contents("output.json", json_encode($db_export, JSON_PRETTY_PRINT));
Which outputs as:
{
"account": {
"username": "test",
"email": "test#domain.com"
}
}
What it's supposed to be:
{
"account": [
{
"username": "test",
"email": "test#domain.com"
}
]
}
Adding [] characters will help. This creates an array inside the array.
$db_export = [
'account' => [[ // <--- Added
'username' => $username,
'email' => $email
]] // <--- Added
];
file_put_contents("output.json", json_encode($db_export, JSON_PRETTY_PRINT));
This is how you get the result you want.
Output :
{ "account": [ { "username": null, "email": null } ] }
I guess it was a little simple :)
I am adding this to explain what is going on with the original answer. You can find this same information in the json_encode php manual page, in the example sections.
With any simple PHP array, json_encode will transform the PHP array into a JSON array:
$simple = array('apple', 'banana', 'coconut');
echo json_encode($simple);
Returns:
["apple","banana","coconut"]
Any associative array will be turned into a json object {} and each associative key will become a property name.
$associative = array('breakfast' => 'apple', 'lunch' => 'banana', 'dinner' => 'coconut');
echo json_encode($associative);
Returns:
{"breakfast":"apple","lunch":"banana","dinner":"coconut"}
In your example, you have an array with an associative key 'account' that contains an array with 2 child elements, each with an associative key.
This is the reason json_encode() is turning your structure into json objects.
In #Smokie's answer, the addition of an extra parent array that is "simple" ie. not keyed with a name, causes json_encode (following it's simple transformation rules) to create a javascript array, which it then sticks the javascript object inside of.
$username = 'test user';
$email = 'foo#bar.com';
$db_export = [
'account' => [[ // <--- Added
'username' => $username,
'email' => $email
]] // <--- Added
];
var_dump($db_export);
Returns:
array(1) {
["account"]=>
array(1) {
[0]=>
array(2) {
["username"]=>
string(9) "test user"
["email"]=>
string(11) "foo#bar.com"
}
}
}
Here I use var_dump as a quick debugging tool to show what the PHP array looks like. The important thing to note is that 'account' is now an array(1) with one element ( the 0th element) that contains your original child array.
Presumably you need this because the assumption is that an account could have multiple accountname/email address pairs. If that isn't the case, I would question why you need to force a useless array. I personally don't see how an 'account' could have multiple username/email pairs associated with it.
With that said, this code should further illustrate how this all works, and why:
$username = 'test user';
$email = 'foo#bar.com';
$db_export = [
'account' => [[ // <--- Added
'username' => $username,
'email' => $email
]] // <--- Added
];
//Add another username/email pair to account
$db_export['account'][] = ['username' => 'test2 user', 'email' => 'test2#bar.com'];
echo json_encode($db_export, JSON_PRETTY_PRINT);
Returns:
{
"account": [
{
"username": "test user",
"email": "foo#bar.com"
},
{
"username": "test2 user",
"email": "test2#bar.com"
}
]
}

PHP - MongoDB: Retrieve Fields from Sub Document with Field Names in Array

Consider an Array
$lettersArray = [A,C,E,G]
and my MongoDB Collection has the following structure.
{
Collection : {
letters:{
A:{...},
B:{...},
...
Z:{...}
}
}
}
Consider that the Letter Sub document is a part of a larger collection. Hence I am using Aggregation.
Right Now I have tried to project -
['$Collection.letters' => ['$elemMatch' => ['$in' => $lettersArray]]
and also tried
['Letters' => ['$in' => [$lettersArray,'$Collection.letters']]
But it didn't work.
In the End, I want result like the following:
[
Collection => [
letters => [
A => [...],
C => [...],
E => [...],
G => [...]
]
]
]
Is there any way to do this?
In PHP you can use array_combine with array_fill to create the empty arrays.
$lettersArray = ['A','C','E','G'];
$letters = array_combine($lettersArray, array_fill(0,count($lettersArray), []));
Array_fill creates an array from index 0, to the count of items in $lettersArray with the contents []
Output:
array(4) {
["A"]=>
array(0) {
}
["C"]=>
array(0) {
}
["E"]=>
array(0) {
}
["G"]=>
array(0) {
}
}
https://3v4l.org/TeoFv
I think you are mistaken in the way you are trying to access the documents' information.
If you take a look at your MongoDB document, you will see that it is in fact not an array, so you should not use $elemMatch to project these fields, but simple projections. In your case, you should project in this way:
[
'$project' => [
'Collection.letters.A' => 1,
'Collection.letters.C' => 1,
'Collection.letters.E' => 1,
'Collection.letters.G' => 1
]
]
By the way, you don't need to use the aggregation framework to compute such a projection. You could just use find(), and use the projection in the options, which are the functions' second argument:
myCollection->find(query, [
'projection' => [
'Collection.letters.A' => 1,
'Collection.letters.C' => 1,
'Collection.letters.E' => 1,
'Collection.letters.G' => 1
]
]);
Cheers,
Charles

best approach to fetch data from old db structure, fix data with php and upload to new schema

We have created a new db schema for old application, which currently has 4375987 rows in a single table with multiple columns. i have to migrate old data to new db schema which will fetch data from one table and be going to insert in multiple db tables.
i need to know the best approaches. should i right down the script in PHP or and other solution. the old db has very large data.
please guide thanks.
Split your row up using a function. Then take each part of the returned result and do your inserts:
See https://3v4l.org/HEFS3
<?php
$old = [
'name' => 'Dave',
'dob' => '1970-01-01',
'blah' => 'blah',
];
function convertRow($row)
{
$new = [
'table1' => [
'name' => $row['name'],
'dob' => $row['dob'],
],
'table2' => [
'blah' => $row['blah'],
],
];
return $new;
}
$data = convertRow($old);
// Now do your inserts
$firstTableData = $data['table1'];
$secondTableData = $data['table2'];
var_dump($firstTableData, $secondTableData);
This outputs:
array(2) { ["name"]=> string(4) "Dave" ["dob"]=> string(10) "1970-01-01" }
array(1) { ["blah"]=> string(4) "blah" }
So you can now take that data and do your inserts for each table. Hopefully this should get you going! :-)

Mongo DB, PHP add or update a field in a document

I have the following document:
{
"_id": ObjectId("5241f1d79b7e7aed05000000"),
"description": {
"nl": "Hallo",
"en": "Hello"
},
"name": "Marc"
}
Now I need to update to update one existing field or add new field to the description. In php I use the update function for Mongo and the following code:
$new_data = array(
'$set' => array(
"description" => array(
"de" => "hallo"
)
)
);
What it does it removes all other fields and just insert the "de" field. I tried replacing $set with $push (which I thought was made for this) but no result also $setOnInsert does not do anything.
How can I solve this problem so that I can either add a new field (if it does not exist) or update if it exist.
Thanks
Just make your update like
{$set: {"description.de": "hello"}}
I guess in your code it would be:
$new_data = array(
'$set' => array(
"description.de" => "hallo"
)
);

Categories