PHP Mongo Query NOT NULL - php

Anyone know the syntax for writing a php-mongo query to use NOT NULL?
I know how to do this when I query for NULL:
<?php
$cursor = $collection->find(array("someField" => null));
Is this even possible?

Yeah, you want the $ne operator, so
$cursor = $collection->find(array("someField" => array('$ne' => null)));

Basically, the same kind of queries you would use on the Mongo console, you pass as an array to the query methods.
In your case, it could be (if you're checking that the field exists - note that the field could just be absent from the document):
array("someField" => array('$exists' => true))
Or to check if it's not equal to null:
array("someField" => array('$ne' => null))
Watch out for the $ in double quotes, since PHP will consider that a variable.

Related

How to find all documents where the value of a field is null or empty

I'm trying to write a simple Mongo query to return all documents where the value of a field is null (or an empty array, I'm not sure what you call it).
Here is my query;
db.getCollection('contact').find({'poco.name.email':false})
Here is a screenshot of my collection using RoboMongo;
Ultimately, I need to transfer this to some PHP. So far I have this working;
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
//not sure what goes here.. something like
//'poco.emails' => null,
]);
return Model_Mongo_Contact::getContacts($conditions, $sort, $fields, $limit, $skip);
That's probably going to be harder to answer without more access to the methods.. Or maybe not I am very new to Mongo it might be really obvious.
I'm not PHP expert but I'll be doing in mongo shell as:
db.collection.find({
$and: [
{"poco.email":{$exists: true}},
{"poco.email":{$ne: []}}
]})
Query above will list all documents where poco.name.email is not missing and is not empty.
The basic concept when looking for an "empty" array or even "non-existent" is to use a property of "dot notation" and search where the 0 index of the array does not exist. This can be achieved with using the $exists operator:
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
'poco.emails.0' => array( '$exists' => FALSE )
]);
That condition is true when either there is no property at all, or if it is something other than an array ( therefore no "0" field property ) or indeed an "empty" array ( since there is no content at the first index ).
This works best when the field is actually "indexed". So if in your "normal" structure you have "sub-documents" inside the array element with say a consistent field named "address" which is indexed as "poco.emails.address", then you are best of pointing to that specific indexed property to see if it $exists or not:
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
'poco.emails.0.address' => array( '$exists' => FALSE )
]);
But if the array consists purely of "values" only and no "sub-documents", then simply testing for the 0 index position of the array as initially demonstrated will be enough.

How to find ActiveRecords which have attribute either equal to value or be null in Yii2

I basically have an active query and I either want to filter that column if it matched the ID or is null
MyTable::find()->andFilterWhere(['in', 'org_id', [null, $org_id]])->all();
currently using this, works fine for the $org_id, but it will not return null values.
I tried this to see if I could get any null results, but no avail
MyTable::find()->andFilterWhere(['in', 'org_id', null])->all();
Any tips?
Correct you query like that:
MyTable::find()
->andFilterWhere(['in', 'org_id', $this->org_id])
->orWhere(['org_id' => null])
->all();
You can specify IS NULL condition with array also, orWhere is enough because this condition does not depend on attribute value.
If you are using a filter of multiple values, the following query will result in cell with null or values in an array:
$query->andWhere(['or', ['in', 'column', $value_array], ['column' => null]]);
To reinforce arogachev's answer, this is a good reference, if you wanted to just query for null results:
https://github.com/yiisoft/yii2/issues/6788
$query->andfilterWhere('org_id' => null)
This query doesn't work because filterWhere removes empty params.
For null results, use:
$query->andWhere('org_id' => null)
To completely answer this question, let's reiterate what we really want.
We need to get all records from some table which have some specific 'field' to be equal either to given $value or to null.
Given that definition, we can translate it directly into Query call:
$query->andWhere(['or', ['field' => $value], ['field' => null]]);
This is somewhat suboptimal in cases when $value is null, because it gives the SQL WHERE (field IS NULL) OR (field IS NULL).
You can mitigate it by wrapping the andWhere call with if statement:
if ($value === null)
$query->andWhere(['field' => null]);
else
$query->andWhere(['or', ['field' => $value], ['field' => null]]);
or depending on your tastes, using ternary operator:
$query->andWhere(
$value === null
? ['field' => null]
: ['or', ['field' => $value], ['field' => null]]
);
In any case, using andFilterWhere completely defeats the purpose of your query, because it exists solely to remove pieces like ['field' => null] from the queries.

PHP isset returns true but should be false

My project is in cakePHP but I think this is an aspect of native PHP that I am misunderstanding..
I have an afterFind($results, $primary = false) callback method in my AppModel. On one particular find if I debug($results); I get an array like this
array(
'id' => '2',
'price' => '79.00',
'setup_time' => '5',
'cleanup_time' => '10',
'duration' => '60',
'capacity' => '1',
'discontinued' => false,
'service_category_id' => '11'
)
In my afterFind I have some code like this:
foreach($results as &$model) {
// if multiple models
if(isset($model[$this->name][0])) {
....
The results of the find are from my Service model so inserting that for $this->name and checking if(isset($model['Service'][0])) should return false but it returns true? if(isset($model['Service'])) returns false as expected.
I am getting the following PHP warning:
Illegal string offset 'Service'
so what's going on here? why does if(isset($model['Service'][0])) return true if if(isset($model['Service'])) returns false?
UPDATE:
I still don't know the answer to my original question but I got around it by first checking if $results is a multidimensional array with
if(count($results) != count($results, COUNT_RECURSIVE))
Use array_key_exists() or empty() instead of isset(). PHP caches old array values strangely. They have to be manually unset using unset()
isset() does not return TRUE for array keys that correspond to a NULL value, while array_key_exists() does.
String offsets provide a mechanism to use strings as if they were an array of characters:
$string = 'abcde';
echo $string[2]; // c
$model is indeed a string for all keys except discontinued.
As for the isset($model['Service'][0]) return value, I'm a bit surprised. This is a simplified test case:
$model = '2';
var_dump(isset($model['Service'])); // bool(false)
var_dump(isset($model['Service'][0])); // bool(true)
There must be a reason somewhere. Will have a dig..

Issue with boolean query in mongo php

I need to perform a query based on the value of some boolean fields. These fields may not exist in some documents, as they were added at a later stage.
I tested the query in the shell and worked ok:
db.product.find({$or: [{approved:true},{$and: [{approved:{$exists:false}}, {sold:{$ne:true}}]}]})
But trying to do the same with the PHP driver doesn't seem to work:
$condA = array('approved' => true);
$condB = array('approved' => array('$exists' => false), 'sold' => array('$ne' => true));
$query = array('pid' => $prodId, '$or' => array($condA, array('$and' => $condB)));
I tested some variants but I'm always getting this error in the log:
assertion 13086 $and/$or/$nor must be a nonempty array
Any hint on what I might be doing wrong? Thanks in advance.
Since multiple "clauses" of a query are interpreted as "and" you don't need the $and in your query. If you take out $and:[ ] you end up with a simpler
{ $or : [ { approved : true }, { approved : {$exists:false}, sold : {$ne:true} } ] }
When you convert that into corresponding PHP that should work for you.

Find field in MongoDB where field is not empty (in PHP)

This may be a very easy thing to do, but I'm pretty new to MongoDB and am having trouble making this word right.
I'm pulling leads from a database, and I only want it to pull records where the email field is not empty. I've tried putting in the statement to skip the record if it's not null, but there are many fields that aren't null, but don't have any characters in them, either. Here is my MongoDB query:
$records = $dbh->find('email' => array('$ne' => null))->limit(2000);
I also tried 'email' => array('$ne' => '')) but that didn't do the trick either.
Is there a simple way to do this? I know in MySQL it would be a simple where email != "" but I'm still learning my way around Mongo :) Thanks!
Try this, you are enclosing into array improperly
$records = $dbh->find(array("email" => array('$ne' => null)))->limit(2000);
Ok, I just figured out a decent way, and will post it for any other "noob" like me who's having the same problem :)
I used '$nin' with an array and it fixed the problem. Here's my query now:
$records = $dbh->find(array("email" => array('$nin' => array(' ','',null))))->limit(2000);
After 3 hours of failing, I managed to do it in a tricky way:
find('field' => array('$regex' => '.*'))
$records = $dbh->find('$or'=>array(
array('email'=>array('$exists' => false)),
array('email'=>array('$ne' => null)),
array('email'=>array('$ne' => ''))
));
You could also do this like
$records = $dbh->find(array('$where' => 'this.email && this.email.length'))->limit(2000);

Categories