Convert PHP mongodb findOne result to old associative array? - php

I'm having issues with the new mongodb driver for php.
While iterator_to_array works ok for ->find, if I only return one document it has MongoDB\Model\BSONDocument format.
$result = $db->clients->findOne(array('_id' => $id));
$result = (array) $result;
In Mongo the document looks something like:
{
"_id" : ObjectId("3894713i4b13iu412"),
"active" : true,
"logo" : "this is logo",
"settings" : {
"email" : "days",
"testMode" : false
},
"stats" : {
"f" : {
"all" : [
{
"count" : NumberLong(15846),
"sum" : NumberLong(149479)
},
{
"count" : NumberLong(15846),
"sum" : NumberLong(148891)
},
{
"count" : NumberLong(15846),
"sum" : {
"1" : NumberLong(15522),
"2" : NumberLong(324)
}
}
]
},
"l" : {
"order" : ISODate("2016-12-05T09:10:53.855+0000"),
"feedback" : ISODate("2016-12-05T08:34:48.403+0000")
}
},
"title" : "hhh.ro",
"url" : "sdfasdf"
}
This will only turn first level elements into an array, but nested document elements still remain MongoDB\Model\BSONDocument;
iterator_to_array doesn't work because this is not something iterable.
How do I convert entire document to an associative array like the old mongo driver or a stdClass?

you can set how the data is returned globally in database->setCollection options, Set typeMap to array
'typeMap' =>[
'document' => 'array',
'root' => 'array'
]
Link to Doc

I couldn't find the setCollection suggested by #Delcon in PHP MongoDB library so I used the below method.
typeMap option can also be set in the options array inside findOne.
$someCollection->findOne(
[],
['typeMap' => ['root' => 'array', 'document' => 'array', 'array' => 'array']]
);
Link to Doc
edit:
You could also pass the options array to the connector to set it globally as described by this Stackoverflow post.
$options = ["typeMap" => ['root' => 'array', 'document' => 'array']];
$conn = new MongoDB\Client("mongodb://localhost:27017", [], $options);

Related

Update MongoDB sub document element based on the Condition using PHP

Here is my JSON Array
{
"_id" : ObjectId("563b57c84abf457b395076f0"),
"project_id" : "563b57c84abf45ce1f5076f1",
"project_task" : [
{
"switch" : "Ball",
"deviceId" : "dasdqwdf124",
"slot" : "2344",
"MigrationStartDate" : "",
"MigrationEndDate" : "",
"MigrationStatus" : "",
"task_id" :12
}
]
}
In this array project_id and task_id (Sub Document element) values are unique.
So in this case i need update my sub document element one at a time When project_id and task_id are equals to given values.
So far i used update function with and condition and findAndModify() function but never worked for me.
Here is my Query using findAndModify()
findAndModify(array('project_id' => "$projectId", 'project_task' => array('task_id' => "$taskId")), array('$set' => array("$column" => "$value")))
Please help me out

PHP/MongoDB $set use for update an array in a collection

I am trying to update() a specific single array in a collection, but while it works fine with $push parameter on a single, specific array, it does not work with a $set parameter.
I don't quite understand logic behind that, because when I use such an example of $pushing the element:
$post_comment = array('$push' =>
array("comments" => array(
"_id" => new MongoId(),
"comment" => htmlspecialchars($_POST['comment']),
"author" => $user->username,
"date" => new MongoDate()
)
)
);
$entries->update(array(
"_id" => $_GET["id"]), $post_comment);
It gives me an array in a MongoDB database which looks more or less like this (with four items pushed in, respectively) :
{
"_id" : "css-clearfix-explained",
"comments" : [
{
"_id" : ObjectId("540cc940af105b19133c9869"),
"comment" : "aaa",
"author" : "maciejsitko",
"date" : ISODate("2014-09-07T21:08:16.215Z")
},
{
"_id" : ObjectId("540cc943af105b19133c986a"),
"comment" : "bbb",
"author" : "maciejsitko",
"date" : ISODate("2014-09-07T21:08:19.542Z")
},
{
"_id" : ObjectId("540cc946af105b19133c986b"),
"comment" : "ccc",
"author" : "maciejsitko",
"date" : ISODate("2014-09-07T21:08:22.968Z")
}
]
}
Which is basically what I want to have, and logically, works fine according to the documentation. But when I try the same with $set as for to edit an individual comment, in the similar fashion as shown:
$edit_comment = array('$set' =>
array("comments" => array(
"_id" => new MongoId($_POST['cmt-id']),
"comment" => htmlspecialchars($_POST['edit-comment']),
"author" => $user->username,
"date" => new MongoDate()
)
)
);
$entries->update(array(
"_id" => $_GET["id"]), $edit_comment);
It outputs four different arrays in place of the previous arrays, to illustrate that, i'll show what happened when I updated first comment "aaa" to "ddd" :
{
"_id" : "css-clearfix-explained",
"comments" : {
"_id" : ObjectId("540cc940af105b19133c9869"),
"comment" : "ddd\r\n ",
"author" : "maciejsitko",
"date" : ISODate("2014-09-07T21:12:10.833Z")
}
}
All the four array elements were pretty much erased and in their place appeared four fields as four independent array elements.
How come? Shouldn't it just work just fine like the example with $push above?
You didn't specify an index within comments. Therefore, $set replaced the array comments with the associated array supplied.
If you want to update a comment, then change your query in the first argument to match a comment by a unique field. Ex, date. In the second argument use a positional $ operator.
Example:
$edit_comment = array('$set' =>
array("comments.$" => array(
"_id" => new MongoId($_POST['cmt-id']),
"comment" => htmlspecialchars($_POST['edit-comment']),
"author" => $user->username,
"date" => new MongoDate()
)
)
);
// this assumes the post date is unique. On second though use something else.
$query = array( "_id" => $_GET["id"], "comments.date" => $_POST['post-date'])
$entries->update( $query, $edit_comment);
Check this out for more info and better explanation:
MongoDB - $set to update or push Array element

Mongodb + PHP => Find query operator in multidimensional array

I need to find in array saved in a document of Mongodb.
Here is the document :
{
"hashtag" : "World",
"topimages" : [
{
"cluster" : "france",
"id_tw" : "477170636327227393"
},
{
"cluster" : "france",
"id_tw" : "477170636327227396"
}
]
}
And I want to search if a document named "World" by key "hashtag", have already a tweet saved in the array "topimages" with an id "id_tw" of value : "477170636327227393"
What I'm trying to do is :
$query = array('hashtag' => "World", array('topsimages.$.id_tw' => "477170636327227393"));
$xpmm->find($query);
I need to search if a document called "World" has already a tweet saved in the array "topimages" by his key "id_tw".
Thanks a lot.
#
Solution :
$query = array('hashtag' => "france", 'topimages.id_tw' => "477170282852286464");
That's ok using :
$query = array('hashtag' => "france", 'topimages.id_tw' => "477170282852286464");
topimages.x would only work if it was a subdocument, not an array. You want $elemMatch (Mongo DB Documentation)
$query = array('hashtag' => "World", 'topsimages' => array("$elemMatch" => array("id_tw" => "477170636327227393")));

Find substring in MongoDB array from another array from PHP

I have a more complex document "schema" saved in Mongo but the part that I need to match looks like this
"tags" : [
{
"tag" : "accompong maroon festival",
"type" : "label"
},
{
"tag" : "jamaica",
"type" : "label"
},
{
"tag" : "maroon warrior",
"type" : "label"
},
{
"tag" : "maroons",
"type" : "label"
},
{
"tag" : "caribbean culture",
"type" : "label"
},
{
"tag" : "rum",
"type" : "label"
}
}
I am using PHP to query the Mongo database and I have to query each document against an array of possible words.
array(
'boxing',
'warrior'
)
I don't know how to write the code in order to try to match the array that I have with the dataset saved in Mongo.
For now I only try to see if the tag is within the array of words
$data = $this->event_model->find_by(
array
(
'tags.tag' => array
(
'$in' => $Words
),
'published' => 'y'
)
);
I've resolved this problem by first creating an array that uses MongoRegex to search through the tags and by adding this array to the $or procedure
$or_array = array();
foreach($Words as $w)
{
$or_array[] = array(
'tags.tag' => new MongoRegex('/.*'. $w .'.*/i')
);
}
$data = $this->event_model->find_by(
array
(
'$or' => $or_array,
'published' => 'y'
)
);

Acces an element in an array, in a subdocument, in a document using MongoDB and Codeigniter

I have this document in the 'families' table:
{
"_id" : {
"$oid" : "51b701a81c1d7bd459000001"
},
"items" : {
"tasks" : [{
"due_date" : "07/06/13",
"assignees" : "Dorel#yahoo.com",
"_id" : {
"$oid" : "51ba0c181c1d7b7c0e00000c"
},
"type" : "task",
"author" : "cornel#gmail.com",
"creation_date" : "13/06/2013",
"name" : "Task0"
}
]
}
}
Using Codeigniter's ActiveRecord Library I'm trying to access an element in the 'tasks' array by doing so ( '$item_id' is the id of the task I'm looking for):
$this->mongo_db->where(array('_id' => $this->session->userdata('family_id')))
->where(array('items.$.$._id' => $item_id));
$query = $this->mongo_db->get('families');
So I tried to use the dot notation and the positional operator. But all I get is an empty array.
Please, help, anyone?

Categories