MongoDB PHP accent problems - php

Assume that I have inserted the following document with PHP (Note the "ó".)
$dbs->insert(array('name' => 'televisión'));
In mongodb database server is saved as follows
{ "name" : "televisi��n" }
If I invoke the findOne method as follow, (NOTE THE ó)
$doc = $dbs->findOne(array('name' => "televisión"));
It return me the correct value
[name] => televisión
Everything fine until here.
So, imagine that from php I need to determine that the document televisión is into mongodb database, but I get the value from an URL without the accent "ó", i.e. television, so.
$doc = $dbs->findOne(array('name' => "television"));
findOne method is returning null, so don't match the document.
Is there any way for this not return null value and can find the document regardless of the accent?
Thanks in advance!

In mongodb database server is saved as follows
{ "name" : "televisi��n" }
That's probably because your shell doesn't show UTF-8 properly.
As for:
Is there any way for this not return null value and can find the document regardless of the accent?
You can do that with the new text search functionality:
<?php
$m = new MongoClient;
$d = $m->test;
$c = $d->so;
// Just dropping here to create a controlled output - no need to do this yourself.
$c->drop();
$c->ensureIndex(
array( 'name' => 'text' ),
array( 'default_language' => 'spanish' )
);
$c->insert( array('name' => 'televisión' ) );
$res = $d->command( array( 'text' => 'so', 'search' => 'television' ) );
var_dump( $res['results'] );
?>
Which outputs:
array(1) {
[0] =>
array(2) {
'score' =>
double(1)
'obj' =>
array(2) {
'_id' =>
class MongoId#6 (1) {
...
}
'name' =>
string(11) "televisión"
}
}
}
For text search to work, you need MongoDB 2.4.x, and you need to specifically enable it with the --setParameter textSearchEnabled=true flag to mongod or add to your code:
$d->command( array( 'setParameter' => 1, 'textSearchEnabled' => true ) );

Related

Deleting a document based off of it's ObjectId [duplicate]

I was successful in deleting documents using other fields but could not delete using "_id" field. The PHP page says that the id should be a string (which it is by default), but what I was trying to do is, giving an id of my own which is an integer, and am doing the following:
This is my document structure:
$document = array (
'_id' => new MongoInt32(1),
'cust_id' => 'abc124'
)
This is how I am trying to delete:
$collection->remove(array('_id' => new MongoId(1)), true);
But this is giving me an error. PHP php manual says:
"To remove a document based on its ID, you need to ensure that you pass the ID as a MongoID object rather than just a string:"
But my id is a int and I cant figure out the process to delete the document referenced by the id.
Your help would be appreciated. Thank You.
You've used a normal integer (MongoInt32) as _id field. And MongoInt32 is not the same as MongoID. They are two different classes. You are suppose to delete it with:
$collection->remove( array( '_id' => new MongoInt32(1) ) );
Additional Information:
MongoId is used as value for an _id field if you don't set a value yourself, such as with:
$collection->insert( array( 'cust_id' => 'abc124' ) );
If you retrieve this document, and var_dump() that you will see:
array(2) {
'_id' =>
class MongoId#6 (1) {
public $$id =>
string(24) "51ee74e944670a09028d4fc9"
}
'cust_id' =>
string(6) "abc124"
}
The note in the docs mean that you can't remove that document now with:
$collection->remove( array( '_id' => '51ee74e944670a09028d4fc9' ) );
But instead you will need to use:
$collection->remove( array( '_id' => new MongoID( '51ee74e944670a09028d4fc9' ) ) );
As last point I'd like to raise that you don't really have to use new MongoInt32(1) in the first place, you can just use:
$document = array (
'_id' => 1,
'cust_id' => 'abc124'
);
You only need MongoInt32/MongoInt64 in case you're on a 32-bit platform (or Windows) and need to deal with large numbers.
This should work:
$collection->deleteOne( array( '_id' => new MongoDB\BSON\ObjectId ($_id )) );
"To remove a document based on its ID, you need to ensure that you pass the ID as a MongoID object rather than just a string:"
Normally what the PHP manual states is true but not for you. You have changed the type of your _id to something other than an ObjectId (aka a MongoId).
With this in mind you need to search by that other object which is a MongoInt32:
$db->collection->remove(array('_id'=>new MongoInt32(1)))

Mongo distinct sort query using PHP driver

Having some trouble issuing a simple query from the PHP Mongo driver.
This is the shell query:
db.testing.distinct('summary.type').sort();
According to the documentation, I can do a db->command to use the distinct query. Here is what I've tried:
$all_types = $db->command(
array(
"distinct" => "summary.type",
"key" => "summary.type"
)
);
var_dump($all_types);
But rather than getting back the data I expect, I only get a cursor with indexes like stats, nscanned and nscannedObjects
What am I doing wrong?
Thanks,
ns
Commands don't return a MongoCursor object, but always just one document. Just like with findOne(). In this returned document, the values array element in the returned array contains an array of all your results:
<?php
$m = new Mongo; $c = $m->demo->pubs; $c->drop();
$c->insert( array( 'name' => 'Betsy Smith', 'city' => 'London' ) );
$c->insert( array( 'name' => 'London Tavern', 'city' => 'London' ) );
$c->insert( array( 'name' => 'Lammars', 'city' => 'Manchester' ) );
$c->insert( array( 'name' => 'Weatherspoons', 'city' => 'Coventry' ) );
$r = $m->demo->command( array(
'distinct' => 'pubs',
'key' => 'city',
'query' => array( 'name' => array( '$ne' => 'Weatherspoons' ) )
) );
var_dump( $r['values'] );
?>
Which returns:
array(2) {
[0] =>
string(6) "London"
[1] =>
string(10) "Manchester"
}
The result you're looking for is actually in the values key of the command's response. If you look at the entire output of var_dump(), you'll see keys for values, stats (which you referred to), and ok.
On the JavaScript console, the collection's distinct() helper function actually handles the unwrapping for you, which you can see when viewing the source:
> db.testing.distinct
function (keyString, query) {
var res = this._distinct(keyString, query);
if (!res.ok) {
throw "distinct failed: " + tojson(res);
}
return res.values;
}
Also, I believe you have an error in the command being issued through the PHP driver. The distinct option should refer to the collection name, and key should refer to the field name. See the Distinct docs for more information on that.

Drupal - PHP Validation

I have some content types (nodes) that are attached to various taxonomies. For specific node types, I want to do some validation on the taxonomy. I do not want to hard-code the nodes types and their corresponding fields that reference the taxonomy. So I put them in array.
However, I am unable to dereference the field names. I've tried double $$, quotes, etc, but can't get it to work. Is what I want to do possible?
Below is a standalone PHP that I am trying to get to work.
<?php
$node = (object) array(
'nid' => NULL,
'vid' => NULL,
'uid' => '1',
'type' => 'price_document',
'language' => 'und',
'field_taxonomy_price' => array(
'und' => array(
array(
'tid' => '94'
)
)
),
);
$nodes_to_check = array("price_document" => "field_taxonomy_price",
"package" => "field_taxonomy_package",
);
if (array_key_exists($node->type,$nodes_to_check)) {
$taxonomy_field = $nodes_to_check[$node->type];
print_r($taxonomy_field);
$tid = $node->field_taxonomy_price ['und'][0]['tid']; // <- this works but, how
//$tid = $node->"$$taxonomy_field" ['und'][0]['tid']; <- can I deref variable?
}
?>
Well, you can do this:
$taxonomy_field = $nodes_to_check[$node->type];
$tid = $node->{$taxonomy_field}['und'][0]['tid];
You don't need the double dollar signs. That's in case you want to do things like this:
$dog = "I am a dog";
$var = "dog";
$$var = "Now I'm a pussycat";
echo $dog; // Output: Now I'm a pussycat

mongo php find $in issue with _id's

I'm fairly new to Mongo and PHP. I've been fine with the relatively simple stuff but I've hit a snag performing a php find within a mongo collection conditionally limited by an array of _id's.
Here's a walkthrough...
// "characters" collection
{ "_id":{"$id":"3f177b70df1e69fe5c000001"}, "firstname":"Bugs", "lastname":"Bunny" }
{ "_id":{"$id":"3f2872eb43ca8d4704000002"}, "firstname":"Elmer", "lastname":"Fudd" }
{ "_id":{"$id":"3f287bb543ca8de106000003"}, "firstname":"Daffy", "lastname":"Duck" }
// "items" collection
{ "_id":{"$id":"4f177b70df1e69fe5c000001"}, "mdl":"carrot", "mfg":"Wild Hare Farms ltd.", "ownerid":{"$id":"3f177b70df1e69fe5c000001"} }
{ "_id":{"$id":"4f2872eb43ca8d4704000002"}, "mdl":"hat", "mfg":"Acme Inc.", "ownerid":{"$id":"3f2872eb43ca8d4704000002"} }
{ "_id":{"$id":"4f287bb543ca8de106000003"}, "mdl":"spaceship", "mfg":"Acme Inc.", "ownerid":{"$id":"3f287bb543ca8de106000003"} }
// Let's say I do a find on the item collection for a specific manufacturer...
$itemOwners = $db->items->find(array("mfg" => "Acme Inc."), array("ownerid"));
// The result looks something like this...
[
"4f2872eb43ca8d4704000002":{"_id":{"$id":"4f2872eb43ca8d4704000002"},"ownerid":{"$id":"3f2872eb43ca8d4704000002"}},
"4f287bb543ca8de106000003":{"_id":{"$id":"4f287bb543ca8de106000003"},"ownerid":{"$id":"3f287bb543ca8de106000003"}}
]
// I'd now like to perform a find on the character collection and get the corresponding owner documents.
// To do that I need to build the $in array from the previous find results...
foreach ($itemOwners as $doc)
$itemOwnersTemp[] = $doc["ownerid"];
$itemOwners = $itemOwnersTemp;
// The resulting array looks like this. I've read that the ids need to be in MongoId format. Seems like they are?
[
{"$id":"3f2872eb43ca8d4704000002"},
{"$id":"3f287bb543ca8de106000003"}
]
// and (finally) the conditional find. The result set is always empty. What am I tripping up on?
$characterDocs = $db->characters->find(array("_id" => array('$in' => $itemOwners));
I've just tried this with slightly modified code:
<?php
$m = new Mongo('localhost:13000', array( 'replicaSet' => 'a' ) );
$db = $m->demo;
$db->authenticate('derick', 'xxx');
// "characters" collection
$c = $db->characters;
$c->insert(array( '_id' => new MongoID("3f177b70df1e69fe5c000001"), 'firstname' => 'Bugs', 'lastname' => 'Bunny' ));
$c->insert(array( '_id' => new MongoID("3f2872eb43ca8d4704000002"), 'firstname' => 'Elmer', 'lastname' => 'Fudd' ));
$c->insert(array( '_id' => new MongoID("3f287bb543ca8de106000003"), 'firstname' => 'Daffy', 'lastname' => 'Duck' ));
// "items" collection
$c = $db->items;
$c->insert(array( '_id' => new MongoId("4f177b70df1e69fe5c000001"), 'mdl' => 'carrot', 'ownerid' => new MongoID('3f177b70df1e69fe5c000001')));
$c->insert(array( '_id' => new MongoId("4f2872eb43ca8d4704000002"), 'mdl' => 'hat', 'ownerid' => new MongoID('3f2872eb43ca8d4704000002')));
$c->insert(array( '_id' => new MongoId("4f287bb543ca8de106000003"), 'mdl' => 'space', 'ownerid' => new MongoID('3f287bb543ca8de106000003')));
// Let's say I do a find on the item collection for a specific manufacturer...
$itemOwners = $db->items->find(array("mdl" => "hat"), array("ownerid"));
// The result looks something like this...
/*[
"4f2872eb43ca8d4704000002":{"_id":{"$id":"4f2872eb43ca8d4704000002"},"ownerid":{"$id":"3f2872eb43ca8d4704000002"}},
"4f287bb543ca8de106000003":{"_id":{"$id":"4f287bb543ca8de106000003"},"ownerid":{"$id":"3f287bb543ca8de106000003"}}
]*/
// I'd now like to perform a find on the character collection and get the corresponding owner documents.
// To do that I need to build the $in array from the previous find results...
foreach ($itemOwners as $doc) {
$itemOwnersTemp[] = $doc["ownerid"];
}
$itemOwners = $itemOwnersTemp;
// The resulting array looks like this. I've read that the ids need to be in MongoId format. Seems like they are?
/*
[
{"$id":"3f2872eb43ca8d4704000002"},
{"$id":"3f287bb543ca8de106000003"}
]
*/
// and (finally) the conditional find. The result set is always empty. What am I tripping up on?
$characterDocs = $db->characters->find(array("_id" => array('$in' => $itemOwners)));
var_dump( iterator_to_array( $characterDocs ) );
?>
And it provides the output that I expect:
array(1) {
["3f2872eb43ca8d4704000002"]=>
array(3) {
["_id"]=>
object(MongoId)#3 (1) {
["$id"]=>
string(24) "3f2872eb43ca8d4704000002"
}
["firstname"]=>
string(5) "Elmer"
["lastname"]=>
string(4) "Fudd"
}
}
Somewhere, I think you're doing a wrong conversion but it's difficult to tell as you don't show the output of PHP.
Instead of this:
$itemOwnersTemp[] = $doc["ownerid"];
Try this:
$itemOwnersTemp[] = new MongoID($doc["ownerid"]);

get mongodb _id object after upsert with php

is it possible to get the new/updated _id after the query?
example code:
$key = array( 'something' => 'unique' );
$data = array( '$inc' => array( 'someint' => 1 ) );
$mongodb->db->collection->update( $key, $data, array( 'upsert' => true ) );
$key is not holding the new/old _id object and i assume that $data will not either because its just an instruction.
Yes -- It is possible using a single query.
MongoDB includes a findAndModify command that can atomically modify a document and return it (by default it actually returns the document before it's been modified).
The PHP drivers don't include a convenient method for this on the collection class (yet -- check out this bug), but it can still be used (note that my PHP is terrible, so I may very well have made a syntax error in the following snippet):
$key = array( 'something' => 'unique' );
$data = array( '$inc' => array( 'someint' => 1 ) );
$result = $mongodb->db->command( array(
'findAndModify' => 'collection',
'query' => $key,
'update' => $data,
'new' => true, # To get back the document after the upsert
'upsert' => true,
'fields' => array( '_id' => 1 ) # Only return _id field
) );
$id = $result['value']['_id'];
Just in case someone stumbles across this question like I did, Mongo will actually modify the input array when you call MongoCollection->save(); - appending the id to the end.
So, if you call:
$test = array('test'=>'testing');
mongocollection->save($test);
echo $test['_id'];
You will have the mongo id for that object.
I ran into this issue and worked around it by querying back the _id after the upsert. I thought I'd add some of my findings in case they're useful to anyone who comes here searching for info.
When the upsert results in a new document being created in the collection, the returned object contains the _id (here's a print_r of an example):
Array
(
[updatedExisting] => 0
[upserted] => MongoId Object
(
[$id] => 506dc50614c11c6ebdbc39bc
)
[n] => 1
[connectionId] => 275
[fsyncFiles] => 7
[err] =>
[ok] => 1
)
You can get the _id from this:
$id = (string)$obj['upserted'];
However, if the upsert resulted in an existing document being updated then the returned object does not contain _id.
Give this a shot :
function save($data, $id = null) {
$mongo_id = new MongoId($id);
$criteria = array('_id' => $mongo_id);
// Wrap a '$set' around the passed data array for convenience
$update = array('$set' => $data);
$collection->update($criteria, $update, array('upsert' => true));
}
So lets say the passed $id is null, a fresh MongoId is created, otherwise it just converts the existing $id to a MongoId object.
Hope this helps :D
The update method returns an array with the ID of the document UPSERTED:
Array
(
[ok] => 1
[nModified] => 0
[n] => 1
[err] =>
[errmsg] =>
[upserted] => MongoId Object
(
[$id] => 5511da18c8318aa1701881dd
)
[updatedExisting] =>
)
You can also set fsync to true in an update/upsert, to get the _id returned to the object that has been passed to the update.
$save = array ('test' => 'work');
$m->$collection->update(criteria, $save, array('fsync' => true, 'upsert' => true));
echo $save['_id']; //should have your _id of the obj just updated.

Categories