MongoDB Upsert not working in PHP - php

I am trying to run an update on my documents, I'm using upsert true but its still overwriting?
$col = "A" . $user->agencyID;
$db = $m->rules;
$collection = $db->$col;
$validValue = $_POST['validValue'];
$id = $_POST['ruleID'];
$document = array(
'tags' => array(
$validValue
)
);
$collection->update(
array(
'_id' => new MongoId($id)
),
array('$set' => $document),
array('upsert'=>true)
);
$validValue is like - Foo Bar
The first value goes in fine but when I try adding a different value it overwrites the first one?

I managed to figure out the problem, I needed $addToSet and also needed to take the array() from arround my $validValue

Actually, use $addToSet which will not push a value into the array if it already exists. This code is untested, please change to fit your needs.
$col = "A" . $user->agencyID;
$db = $m->rules;
$collection = $db->$col;
$validValue = $_POST['validValue'];
$id = $_POST['ruleID'];
$document = array(
'tags' => array(
$validValue
)
);
$collection->update(
array(
'_id' => new MongoId($id)
),
array('$addToSet' => array('tags' => $document))
);

Related

Use Result of Aggregation MongoDB in PHP

I have this code:
$data = $collection->aggregate(
array(
'$group'=> array(
'_id' => $fn,
'massi' => array(
'$max' => $dnameth_value
)
)
)
);
I execute this query and I want to obtain only MAX Value, and use this in variable.
I tried this code :
$data=$collection->aggregate(array( '$group'=> array('_id'=>$fn,'massi'=>array('$max'=>$dnameth_value))));
var_dump( $data['result'] );
$func = function($value) {
return $value->massi;};
$massi = array_map($func, $data['result']);
var_dump($massi);
Output in the image attach
When you execute the query, the return value of the aggregate() helper method is an array with two elements: ok with a value of double(1) as well as a result element containing an array of all the documents that made it through the whole pipeline.
For instance, if you want to group all the documents by the field my_key and you want to obtain the maximum dnameth_value from that group, and you execute this aggregation operation
<?php
$m = new MongoClient;
$collection = $m->test->collection;
$fn = '$my_key';
$dnameth_value = '$dnameth_value'
$data = $collection->aggregate(
array(
'$group'=> array(
'_id' => $fn,
'massi' => array(
'$max' => $dnameth_value
)
)
)
);
var_dump( $data['result'] );
?>
you should expect the result array from $data['result'] to come in the following form (for example):
…
array (
'_id' => 'value',
'massi' => double(13),
),
array (
'_id' => 'other_value',
'massi' => double(9),
),
array (
'_id' => 'another_value',
'massi' => double(4),
),
…
Note: Because the aggregation framework returns all of its results as one document over the network, the full result is limited to 16MB. There are also memory limits internally, so it is always wise to restrict the data coming through the pipeline with an operator as soon as you can.
So, with your request, you basically would want to map all the massi values from the array into another array variable using array_map():
<?php
$m = new MongoClient;
$collection = $m->test->collection;
$fn = '$my_key';
$dnameth_value = '$dnameth_value'
$data = $collection->aggregate(
array(
'$group'=> array(
'_id' => $fn,
'massi' => array(
'$max' => $dnameth_value
)
)
)
);
var_dump( $data['result'] );
$func = function($value) {
return $value['massi'];
};
$massi = array_map($func, $data['result']);
var_dump($massi);
?>
Now, suppose you are grouping all the documents in the collection then specify an _id value of null to calculate accumulated values for all the input documents as a whole. The resulting array will have one element which you can access by its index:
<?php
$m = new MongoClient;
$collection = $m->test->collection;
$fn = 'null';
$dnameth_value = '$dnameth_value'
$data = $collection->aggregate(
array(
'$group'=> array(
'_id' => $fn,
'massi' => array(
'$max' => $dnameth_value
)
)
)
);
var_dump( $data['result'] );
$massi = $data['result'][0]['massi'];
var_dump($massi);
?>

Using NotIn & Regex in MongoDB with PHP

I have a table with some user email address like:
johndoe#somemail.com
test#test_mail.com
test2#test_mail.com
admin#company_mail.com
janedoe#someothermail.com
sales#company_mail.com
mruser#validmail.com
I want to get the user list with emails not ending with #test_mail.com OR #company_mail.com.
I succeeded this with following mongo query:
db.users.find({
userEmail: {
$nin: [/#test_mail.com$/,/#company_mail.com$/]
}
})
I trid to run the same query in PHP with following code but couldn't make it work:
$criteria = array(
"userEmail" => array(
'$nin' => array(
'$regex' => new \MongoRegex("/#test_mail.com|#company_mail.com/i")
)
)
);
$cursor = $collection->find($criteria);
Any suggestions?
The correct way to apply this is with a singular MongoRegex object and the $not operator to reverse the condition:
$cursor = $users->find(array(
"userEmail" => array(
'$not' => new MongoRegex('/\#test_mail\.com$|\#company_mail\.com$/i')
)
));
foreach ( $cursor as $doc ) {
var_dump( $doc );
}
The same applies to $nin where you can actually specify a "regex" argument, but it must be an regular expression "object" type and not the operator form:
$cursor = $user->find(array(
"userEmail" => array(
'$nin' => array(new MongoRegex('/\#test_mail\.com$|\#company_mail\.com$/i'))
)
));
foreach ( $cursor as $doc ) {
var_dump( $doc );
}
But not really necessary as you are not providing an "array" of different values, the regular expression can represent the "or" condition itself.
You shouldn't use $nin in this case, I would try something like this:
$criteria = array(
"userEmail" => array(
'$not' => array(
'$or' => array(
'$regex' => new \MongoRegex("/#test_mail\.com$/i"),
'$regex' => new \MongoRegex("/#company_mail\.com$/i"),
),
),
)
);
UPD:
you can try this:
$criteria = array(
'$not' => array(
'$or' => array(
"userEmail" => array('$regex' => new \MongoRegex("/#test_mail\.com$/i")),
"userEmail" => array('$regex' => new \MongoRegex("/#company_mail\.com$/i")),
),
),
)
);

php mongodb '$or' regex search

i'm trying to query mongodb "videos" collection to find results by "title" or "tags" fields... it keeps returning 0 results even when i search for terms i know are in the title and/or tags... any help would be appreciated
<?php
$user_query = preg_replace("/[[:blank:]]+/"," ", $_GET['q']);
$arr_query = explode(' ', $user_query);
foreach ($arr_query as $q) {
$title[] = '/'. $q .'/i';
$tags[] = '/'. $q .'/i';
}
$who=array(
'$or' => array(
array('$in' => array('$regex' => $title)),
array('$in' => array('$regex' => $tags))
)
);
$vids=$videos->find($who);
?>
You need to specify some fields for your $in:
$who=array('$or' => array(
array('somefield' => array('$in' => array(new MongoRegex($title)))),
array('otherotherfield' => array('$in' => array(new MongoRegex($tags))))
));
So it works by saying saying: if some field is in a range of some values
http://docs.mongodb.org/manual/reference/operator/in/
Edit
That might still not work because of the embedded $regex. If this is the case then you can try:
$who=array('$or' => array(
array('somefield' => new MongoRegex($title)),
array('otherotherfield' => new MongoRegex($tags))
));
Edit
If either of those queries don't work you can do:
$who = array('$or' => array());
foreach($arr_query as $q){
$who['$or'][] = array('title' => new MongoRegex("/^$q/"));
$who['$or'][] = array('tags' => new MongoRegex("/^$q/"));
}
Something like that should work, again it is untested but if my memory serves me right that should do it.
Another edit
This works perfectly for me:
$mongo = new Mongo();
$db = $mongo->tstvid;
$videos = $db->videos;
$videos->insert(array('title' => 'test1', 'tags' => array('h','h')));
$videos->insert(array('title' => 'test2', 'tags' => array('h','h')));
$videos->insert(array('title' => 'test3', 'tags' => array('h','h')));
$videos->insert(array('title' => 'tst3', 'tags' => array('h','test')));
$user_query = preg_replace("/[[:blank:]]+/"," ", "test");
$arr_query = explode(' ', $user_query);
if (count($arr_query) > 1) {
$who = array(
'$or' => array()
);
foreach ($arr_query as $q) {
$who['$or'][] = array('title' => new MongoRegex("/^". $q ."/i"));
$who['$or'][] = array('title' => new MongoRegex("/^". $q ."/i"));
}
} else {
$regex=new MongoRegex("/^". $user_query ."/i");
$tregex=new MongoRegex("/^". $user_query ."/i");
$who=array(
'$or' => array(
array('title' => $regex),
array('tags' => $tregex)
)
);
}
$vids=$videos->find($who);
$results="";
$i=0;
foreach($vids as $vid){
$results .= "<li>".$vid['title']."</li>\n";
$i++;
}
if($i==0){
$results="<em>No results found</em>";
}
echo $results;
And it outputs:
test1
test2
test3
tst3
So I am unsure what is wrong but I would recommend double checking your script is breaking up the keywords right and the schema is being searched right by issuing these queries in the console as well.
It should be noted I also tried this with:
$user_query = preg_replace("/[[:blank:]]+/"," ", "test h");
And it worked as well.
$search_string = preg_replace("/[^A-Za-z0-9]/", " ", $_GET['q']);
$search_string = $search_string;
//Connecting mongoDB
$dbhost = 'localhost';
$dbname = 'yourdbname';
$port = '27017';
$m = new MongoClient();
$db = $m->$dbname;
if($m){
// select a collection
$videos = $db->videos;
// search for title and tags
$searchQuery = array(
'$or' => array(
array(
'title' => array(
'$regex' => $search_string,
),
),
array(
'tags' => array(
'$regex' => $search_string,
),
),
)
);
$cursor = $videos->find($searchQuery);
foreach ($cursor as $doc) {
var_dump($doc);
//or what ever you want
//var_dump($doc['title']);
}
else{
echo "Collection videos cant select :( <br>";die();
}
Thinks this will help. :D

php mongodb - can't get upsert working

I'm running the following code and it works great, if no record exists it creates a new one. What I'm trying to do is modify this query so that the 'v' field also increases +1 but I'm not having any luck. Can someone help me out?
$result = $collection->update(
array('k'=>md5(SITE_ID.'-'.$_SERVER['HTTP_X_FORWARDED_FOR'])),
array('$set'=>
array(
'k'=>md5(SITE_ID.'-'.$_SERVER['HTTP_X_FORWARDED_FOR']), 'st'=>SITE_ID,
'ur'=>$_GET['u'],
'ts'=>time(),
'dt'=>date('Ymd'),
'ur'=>$_GET['p'],
'v'=>1
),
array(
'$inc' => array('v' => 1)
),
),
array('upsert'=>true)
);
Put both the $set and the $inc in a single object:
$result = $collection->update(
array('k'=>md5(SITE_ID.'-'.$_SERVER['HTTP_X_FORWARDED_FOR'])),
array(
'$set'=> array(
'k'=>md5(SITE_ID.'-'.$_SERVER['HTTP_X_FORWARDED_FOR']), 'st'=>SITE_ID,
'ur'=>$_GET['u'],
'ts'=>time(),
'dt'=>date('Ymd'),
'ur'=>$_GET['p']
),
'$inc' => array('v' => 1)
),
array('upsert'=>true)
);
You can use the $inc modifier liek:
{ $inc : { field : value } }
So in your case:
$result = $collection->update(
array('k'=>md5(SITE_ID.'-'.$_SERVER['HTTP_X_FORWARDED_FOR'])),
array('$set'=>
array(
'k'=>md5(SITE_ID.'-'.$_SERVER['HTTP_X_FORWARDED_FOR']), 'st'=>SITE_ID,
'ur'=>$_GET['u'],
'ts'=>time(),
'dt'=>date('Ymd'),
'ur'=>$_GET['p'],
array('$inc' => array('v' => 1))
),
),
array('upsert'=>true)
);
I just saw you're actually using the field though the example above should work.
Here's an example in the PHP doc: http://php.net/manual/en/mongocollection.update.php#example-1470

How to fetch data from a collection named group in mongodb using PHP code

This is my PHP code for fetching data from a collection in mongodb:
$m = new Mongo('localhost');
$m->connect();
$db = $m->mydb;
$collection = $db->fields_current;
$cursor = $collection->find();
foreach ($cursor as $obj) {
echo $obj["title"] . "\n";
}
The code works fine for the collection fields_current. But, I have a collection like this fields_current.node where node is the named group of the collection. How do I fetch data from the named group.
Edit:
After following PeterM's answer I am getting an empty MongoCursor object. This is my new code:
$m = new Mongo('localhost');
$m->connect();
$db = $m->mydb;
$collection = $db->fields_current;
$query = array(array('group_name' => 'node', 'type' => 'content-type'), array('title' => 1)); // SELECT title FROM fields_current WHERE group_name = 'node' AND type = 'content-type'
$cursor = $collection->find($query);
foreach ($cursor as $obj) {
echo $obj["title"] . "\n";
}
Some more details: I am using Drupal and node refers to the 'node' table, type is the 'node-type'. The collection name is fields_current.node and the record structure is this:
array (
'_id' => new MongoInt32(37),
'_type' => 'node',
'_bundle' => 'content-type',
'_revision_id' => new MongoInt32(37),
'nid' => new MongoInt32(37),
'vid' => new MongoInt32(37),
'type' => 'content-type',
'language' => 'und',
'title' => 'title',
'uid' => new MongoInt32(1),
'status' => new MongoInt32(1),
'created' => new MongoInt32(1342065549),
'changed' => new MongoInt32(1342065549),
'comment' => new MongoInt32(1),
'promote' => new MongoInt32(0),
'sticky' => new MongoInt32(0),
'tnid' => new MongoInt32(0),
'translate' => new MongoInt32(0),
'field_cutom_field' =>
array (
'value' => 'foobar',
),
)
$cursor = $collection->find(array('node' => 'group_name'));
See http://www.php.net/manual/en/mongo.sqltomongo.php for more examples
Since its Drupal you do not have to specify the database name, just like when you write queries for MySql. And also there is a different function for getting a collection object.
// Suppose you have a collection called 'collection_name', then you can get its object using this code.
$collection = mongodb_collection('collection_name');
// Suppose you have a collection called 'collection_name.group', where 'group' is the named group of this collection, then you can get its object using this code.
$collection = mongodb_collection('collection_name', 'group');
// Rest of the operations will be same.
$cursor = $collection->find(array('type' => 'content-type'));
foreach ($cursor as $obj) {
....
// Do your work...
....
}

Categories