Using NotIn & Regex in MongoDB with PHP - 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")),
),
),
)
);

Related

MongoDB Upsert not working in 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))
);

PHP - Inserting to an array by calling a method that returns both key and value

I'm trying to call methods while building an array. I am building a fairly large config array which contains many re usable blocks.
This is the array that I'd like to get:
array(
"masterKey" => array(
"myKey" => array(
"valueField" => "hi"
),
"anotherKey" => array(
"valueField" => "hi again"
)
....
)
);
This is how I'd like to generate it:
array(
"masterKey" => array(
self::getValueField("myKey", "hi"),
self::getValueField("anotherKey", "hi again"),
...
)
);
private static function getValueField($key, $value)
{
return array($key =>
"valueField" => $value
);
}
But this gives me
array(
"masterKey" => array(
[0] => array(
"myKey" => array(
"valueField" => "hi"
)
),
[1] => array(
"anotherKey" => array(
"valueField => "hi again"
)
)
)
);
Instead of constructing the "masterKey" field as a literal, merge the arrays returned by self::getValueField:
array(
"masterKey" => array_merge(
self::getValueField("myKey", "hi"),
self::getValueField("anotherKey", "hi again"),
...
)
);
Just want to add that, for #giaour answer to work, code for the getValueField function should be:
<?php
private static function getValueField($key, $value)
{
return array(
$key => array(
"valueField" => $value
)
);
}

PHP mongo aggregation: match multiple values on same field

I need the pipeline to match documents where field 'modelName' is equal to 'movies' or 'tv_shows'. I tried the code below but it matches only 'tv_shows' and ignores 'movies'.
$match = array('$match' => array('modelName' => 'movies', 'modelName' => 'tv_shows'));
Whole script:
<?php
$connection = new MongoClient;
$collection = $connection -> selectDB("getglue") -> selectCollection("gg");
MongoCursor::$timeout = -1;
$match = array('$match' => array('modelName' => 'movies', 'modelName' => 'tv_shows'));
$group = array('$group' => array('_id' => '$title', 'total' => array('$sum' => 1)));
$sort = array('$sort' => array('total' => -1));
$limit = array('$limit' => 7);
$pipeline = array($match, $group, $sort, $limit);
$out = $collection -> aggregate($pipeline);
echo json_encode($out, JSON_PRETTY_PRINT);
?>
Make use of the $or operator:
$match = array('$match' =>
array('$or' => array(array("modelName" => "movies"),
array("modelName" => "tv_shows"))
)
);
An array in PHP is actually an ordered map. A map can have only one value for any key, and the last added value will override any previous values for the same key. So, in the below, tv_shows which is the last added value for the key - modelName will be associated as the key's only value. And that is why you get the results only for modelname of tv_shows.
'$match' => array('modelName' => 'movies', 'modelName' => 'tv_shows')

mongodb $nin not work in php

Current Code:
$doc = array('ooxx' => array(1,2,3,4,5));
datamodel()->insert($doc);
$doc2 = array('ooxx' => array(6,7,8,9));
datamodel()->insert($doc2);
$macher = array('ooxx'=>array('$exists' => true), 'ooxx' => array('$nin'=>array(6)));
$res = datamodel()->findOne($macher);
print_r($res);
When I replace the $macher with bellow, it does work well, why? is this a bug of mongodb?
$macher = array( 'ooxx' => array('$nin'=>array(6)), 'ooxx'=>array('$exists' => true));
It doesn't work because the keys have the same name and one overwrites the other. So the "keys" need to be unique.
If you have two conditions for the same key you use the $and operator which takes an array of arguments:
$matcher = array(
'$and' => array(
array( 'ooxx' => array( '$nin' => array(6) ) ),
array( 'ooxx' => array( '$exists' => true ) )
)
)
Or for the JSON minded:
{
"$and": [
{ "ooxx": { "$nin": [6] } },
{ "ooxx": { "$exists": true } }
]
}
Which is a valid structure where what you are writing is not.

Loop Through Specific Associative Array In PHP

I am trying to loop through only a specific sub array in PHP with foreach. Example array:
$testData = array(
$test1=array(
'testname'=>'Test This',
'testaction'=>'create user',
$testData = array(
'item'=>'value',
'foo'=>'bar',
'xyz'=>'value'
),
$anotherArray = array()
),
$test2=array(
'testname'=>'Test That',
'testaction'=>'get user',
$testData = array(
'item'=>'value',
'foo'=>'bar',
'xyz'=>'value'
),
$anotherArray = array()
)
);
And now I am going to go through each test and set some logic based on the name and action, but then need to do several tests on the data. Not sure how to only get $test1's $testData and not $test1's $anotherArray data. I have the following but it doesn't work:
foreach($testData as $test => $section){
foreach($section['testData'] as $field => $value){
\\code
}
}
Any help is appreciated! Thanks!
Try this instead:
$testData = array(
'test1'=>array(
'testname'=>'Test This',
'testaction'=>'create user',
'testData' => array(
'item'=>'value',
'foo'=>'bar',
'xyz'=>'value'
),
'anotherArray' => array()
),
'test2'=>array(
'testname'=>'Test That',
'testaction'=>'get user',
'testData' => array(
'item'=>'value',
'foo'=>'bar',
'xyz'=>'value'
),
'anotherArray' => array()
)
);

Categories