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
Related
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);
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
I have a collection in mongodb which looks like this.
"_id" : ObjectId("554c5397ccfff21e103c9869"),
"name" : "test",
"color" : [
"552ced22ccfff2d8183c986a_Jellow",
"551fdd24ccfff2362e3c9869_test"
],
"updated_at" : ISODate("2015-05-08T06:11:35.303Z"),
"created_at" : ISODate("2015-05-08T06:11:35.303Z")
I want to update only one value in the array color But when i try to update the array it removes all the values from the color array and replaces it by the new value.
Here is the code. (I AM USING JESSENGER MONGODB PACKAGE FOR LARAVEL)
$query->where($field,'regexp','/^('.$id.')_.*/')->update([$field=>$id.'_'.$name]);
How should i do it.??
What you wanna do is, either change your schema as {key: value} pair and then follow this tutorial, that will help you to sort out your problem. OR you can get all the values from color array and replace with new value and then update your document (I would not go for it coz it is a dirty approach!).
EDIT
Hey Bud! I founded this, on jenssenger docs:
Push
Add an items to an array.
DB::collection('users')->where('name', 'John')->push('items', 'boots');
DB::collection('users')->where('name', 'John')->push('messages', array('from' => 'Jane Doe', 'message' => 'Hi John'));
If you don't want duplicate items, set the third parameter to true:
DB::collection('users')->where('name', 'John')->push('items', 'boots', true);
Pull
Remove an item from an array.
DB::collection('users')->where('name', 'John')->pull('items', 'boots');
DB::collection('users')->where('name', 'John')->pull('messages', array('from' => 'Jane Doe', 'message' => 'Hi John'));
You need to use the $set operator. Not sure how it's done in Jessenger Mongodb, but it might be something like:
$query->where($field,'regexp','/^('.$id.')_.*/')
->update(['$set' => [ $field=>$id.'_'.$name]]);
Why don't change your data like this:
"_id" : ObjectId("554c5397ccfff21e103c9869"),
"name" : "test",
"color" : [
{ "id":"552ced22ccfff2d8183c986a", "name":"Jellow"},
{ "id":"551fdd24ccfff2362e3c9869", "name":"test"}
],
"updated_at" : ISODate("2015-05-08T06:11:35.303Z"),
"created_at" : ISODate("2015-05-08T06:11:35.303Z")
then you can update element by id.
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'
)
);
I'm trying to add php array to MongoDB document
{
"_id" : ObjectId("51b043e1d07a4e9e06000004"),
"comments" : {
"count" : 0,
"array" : []
}
}
array:
$array = array(
"user_id" => $comment["user_id"],
"text" => $comment["text"]
);
Using this:
$this->database->Collection->update(array("_id" => new MongoId($comment["object_id"])), array('$push' => $array);
However, it doesn't seem to work and I can't find why. I don't know MongoDb well yet... Thanks
The value of the $push needs to be another PHP array with a key that names the array field to update and a value that's the element to add. So in this case it would be:
$this->database->Collection->update(
array("_id" => new MongoId($comment["object_id"])),
array('$push' => array("comments.array" => $array)));