Issue with boolean query in mongo php - 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.

Related

Get the last N entries in ascending order

How can I get the last N entries from MongoDB in a ascending order in PHP?
this is the code im using right now the gets me the last 60 entries but it gives me in a descending form I need it in a ascending form.
<?php
header("Content-type: text/json");
require ($_SERVER['DOCUMENT_ROOT'] . '/grafic/mongodb_php/vendor/autoload.php');
$client = new MongoDB\Client;
$traficodb = $client->traficodb;
$trafico_total = $traficodb->trafico_total;
$filter = [];
$options = ['sort' => ['time_stamp' => -1], 'limit' => 60];
$show = $trafico_total->find($filter, $options);
foreach ($show as $collection) {
$json[]= [strtotime($collection["time_stamp"])*1000, (int)$collection["tx"], (int)$collection["rx"]];
}
echo json_encode($json);
?>
For example if I have rows with timestamp: 1,2,3,4,5,6,7,8,9. I want result shown as 5,6,7,8,9 and not as 9,8,7,6,5
If it's only a relatively small number of results which you are not "paging" ( i.e using limit and skip ) then the most efficient action would be to simply "reverse" the returned results after converting the MongoDB\Driver\Cursor as returned from MongoDB\Collection::find() to an "array".
This is what the Cursor->toArray() method of the driver does, along with array_reverse() as a standard PHP function.
$filter = [];
$options = ['sort' => ['time_stamp' => -1], 'limit' => 60];
$show = array_reverse($trafico_total->find($filter, $options)->toArray());
Then as you iterate the list the results are in ascending order, being the "reverse" of what the cursor returned them as.
Alternately you could use use aggregate()
$show = $tracfico_total->aggregate([
[ '$match' => [] ],
[ '$sort' => ['time_stamp' => -1 ] ],
# [ '$skip' => $itemsInPage ],
[ '$limit' => 60 ],
[ '$sort' => ['time_stamp' => 1 ] ]
]);
And you would typically $skip through previous results before applying your limit, then re-sort the final output. But it really does not add much to what the regular query already does, and the regular query probably does it more efficiently.
There generally is little point asking the database to do things that don't actually "reduce" the results to be returned, so you typically would not perform this on the server unless you had something else to do "on the server" with the results which reduced what was to be returned.
The other case would be typically for a "large resultset" which would be more suited to iterating a cursor. In that case the aggregation approach would be recommended as opposed to converting the cursor to an array "in memory" instead of simply iterating the results in the returned order.

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.

MongoDB regex multiple query with $and

I'm having problem to achieve this.
I have this piece of code which I had tested in Rock Mongo and it works fine.
array(
'TEST' =>
array( '$in' =>
array( new MongoRegex('/^(?!TESTVALUE)/$ig'))
)
)
Above piece of code return me all documents which haven't value "TESTVALUE" for the key "TEST".
Now what I want to achieve?
First I don't know how to write piece of code to fetch all documents which haven't values "TESTVALUE" & "SECONDVALUE" for the key "TEST".
That will be something like this:
array(
'TEST' =>
array( '$in' =>
array( new MongoRegex('/^(?!TESTVALUE)/$ig'),new MongoRegex('/^(?!SECONDVALUE)/$ig') )
)
)
And also I will need above piece of code written in PHP.
Any kind of help or suggestions is welcome and will be appreciated.
Thanks in advance
I don't think you can use $in like that, but this should work:
'TEST' => array('$and' => array(
array('$regex' => new MongoRegex('/^(?!TESTVALUE)/$ig'),
array('$regex' => new MongoRegex('/^(?!TESTVALUE)/$ig')))
something to that effect (untested)
Your queries and your description seem to contradict each other. If you want a query for all documents which don't have some string as the field value, why are you using regexes? Do you not want the value to be a substring of the field value? If you just want to do a query like "find documents where the value of the TEST field is not "X" or "Y", use $nin ("not in"):
db.collection.find({ "TEST" : { "$nin" : ["X", "Y"] } })
If the field should match multiple regexes, then either combine them into a single regex or combine the conditions with $and.

PHP Mongo Query NOT NULL

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.

Mongo DB $or query in PHP

I can't figure out for the life of my to select from a collection with the or parameter. It's not working at all for me and I can't really find any documentation on it for php.
Here is my example code that doesn't return anything even though they exist in the collection:
$cursor = $products->find(
array(
'$or' => array(
"brand" => "anti-clothes",
"allSizes" => "small"
)
)
);
The $or operator lets you use boolean or in a query.
You give $or an array of expressions, any of which can satisfy the query.
You provided only one element in the array. Use:
find(array('$or' => array(
array("brand" => "anti-clothes"),
array("allSizes" => "small")
)));

Categories