$db->akis->update(
array("h" => (string) $_SESSION["_id"], "m" => array('$exists' => false)),
array('$set' => array("k" => $name)),
array("multiple" => true)
);
what i did in here is, if there is an m field, do not update k. What I want to add is, "if m field exists" update i instead of k field, how can I manage this ?
thank you
I think you will need to do two separate queries here. That is just too conditional for MongoDB query parser to handle.
So you will need to put your logic into two separate queries with the second looking like:
$db->akis->update(
array("h" => (string) $_SESSION["_id"], "m" => array('$exists' => true)),
array('$set' => array("i" => $name)),
array("multiple" => true)
);
Running one after the other.
Related
I have three working queries:
To find the rows with keyword in title field
$cursor = $collection->find(['title' => array('$regex'=>new MongoRegex($title_query))])->sort(array('timestamp'=>-1));
To find the rows with keyword in the author field
$cursor = $collection->find(['author' => array('$regex'=>new MongoRegex($author_query))])->sort(array('timestamp'=>-1));
To find the rows within a date range
$rangeQuery = array('timestamp' => array( '$gte' => $from_Id, '$lte' => $to_Id ));
$cursor = $collection->find($rangeQuery)->sort(array('timestamp'=>-1));
I want to combine the queries into 1&2, 1&3 and 2&3. However I am not able to write the correct query...
Here is my query for combining 1&2:
$cursor = $collection->find('title' => array('$regex'=>new MongoRegex($title_query)),
'author' => array('$regex'=>new MongoRegex($author_query)))->sort(array('timestamp'=>-1));
query for combining 1&3:
$rangeQuery = array('timestamp' => array( '$gte' => $from_Id, '$lte' => $to_Id ));
$cursor = $collection->find($rangeQuery, ['title' => array('$regex'=>new MongoRegex($title_query))])->sort(array('timestamp'=>-1));
Can anyone tell me how to write the correct query?
The $regex query operator should not be necessary if you are using the BSON regex type (i.e. MongoRegex in the PHP driver). Let's rewrite the original three queries:
Matching keyword in title, sorted by time descending:
$collection->find([
'title' => new MongoRegex($title_query),
])->sort(['timestamp' => -1]);
Matching keyword in author, sorted by time descending:
$collection->find([
'author' => new MongoRegex($author_query),
])->sort(['timestamp' => -1]);
Matching within a date range, sorted by time descending:
$collection->find([
'timestamp' => [
'$gte' => $from_Id,
'$lte' => $to_Id,
],
])->sort(['timestamp' => -1]);
There are several errors in the combined query examples you shared in the OP. For the "1&2" query, you were not passing an array as the first argument to find(), so that would have been a syntax error. For the "1&3" query, you're only passing the timestamp range as find() criteria, and the title regex is being incorrected passed as the second find() argument, which is reserved for specifying a project (i.e. which fields to return).
Combining the three queries is actually as easy as merging the criteria arrays. For example, we could combine all three like so:
$collection->find([
'title' => new MongoRegex($title_query),
'author' => new MongoRegex($author_query),
'timestamp' => [
'$gte' => $from_Id,
'$lte' => $to_Id,
],
])->sort(['timestamp' => -1]);
In some cases, it's not possible to merge criteria for the same field. For that reason, MongoDB has an $and query operator (see the examples for some use cases); however, in the examples above, the criteria is simple enough that you can simply combine the arrays.
here expample of my data:
'_id' => new MongoId("54087e076c03943c3c8b456b"),
'fornitureFuture' =>
array (
'0' =>
array (
'data_start'▼ => new MongoDate(1412114400, 0),
'data_end' => new MongoDate(1414710000, 0),
'f1' => '65',
'f2' => new MongoInt32(0),
'f3' => '45',
'fornitore' => new MongoId("5346cb2ab9d6f0021e6b18a0"),
),
'1' =>
array (
'data_start' => new MongoDate(1420066800, 0),
'data_end' => new MongoDate(1427752800, 0),
'f1' => '63.75',
'f2' => new MongoInt32(0),
'f3' => '70.4',
'fornitore' => new MongoId("533406896c0394a62c8b4569"),
),
i need to find if exist a data in fornitureFuture with my MongoDate between data_start and data_end ...
first group data_start is 10/01/2014 and data_end 10/31/2014
Second group data_start is 01/01/2015 and data_end 03/31/2015
Something like:
//today is 09/19/2014
$dataTest = mktime(0,0,0,date('n')+2,14,date('Y')); //return 11/14/2014
$testMese = $this->db->getOne('MyCollection', array('_id'=> new \MongoId($thisPodPdr['_id']), 'fornitureFuture.data_start'=>array('$lte'=> new \MongoDate($dataTest)) , 'fornitureFuture.data_end'=>array('$gt'=> new \MongoDate($dataTest)) ) , array('fornitureFuture'=>1) );
I expect empty response but return the record..
2 example:
$dataTest = mktime(0,0,0,date('n')+7,14,date('Y')); //return 04/14/2015
$testMese = $this->db->getOne('MyCollection', array('_id'=> new \MongoId($thisPodPdr['_id']), 'fornitureFuture.data_start'=>array('$lte'=> new \MongoDate($dataTest)) , 'fornitureFuture.data_end'=>array('$gt'=> new \MongoDate($dataTest)) ) , array('fornitureFuture'=>1) );
return correctly empty!
I need to test in the same block ...something like
'fornitureFuture.$.data_start'=>array('$lte'=> new \MongoDate($dataTest)) , 'fornitureFuture.$.data_end'=>array('$gt'=> new \MongoDate($dataTest))
but dont work .
the \ is from namespace and this->db->getOne(collection,$query,$fields) is my function like $this->collection->findOne($query,$fields);
No syntax error.
sorry for my english and thanks for the help
Your first example, which returns 2 results when you expect none, runs the following query:
[
'_id' => new MongoId(...),
'fornitureFuture.data_start' => ['$lte' => new MongoDate(1418533200)],
'fornitureFuture.data_end' => ['$gt' => new MongoDate(1418533200)],
]
The example document you provided has two array elements, with the following date ranges:
1412114400 to 1414710000
1420066800 to 1427752800
This document matches because 1412114400 (of the first element) is less than 1418533200, and 1427752800 (of the second element) is greater than 1418533200. By simply referring to fornitureFuture.data_start and fornitureFuture.data_end, MongoDB's query matcher will be satisfied if any array element's sub-field meets the criteria.
You likely want to restrict start/end criteria to same array element, in which case $elemMatch is what you're looking for:
[
'_id' => new MongoId(...),
'fornitureFuture' => [
'$elemMatch' => [
'data_start' => ['$lte' => new MongoDate(1418533200)],
'data_end' => ['$gt' => new MongoDate(1418533200)],
],
],
]
This criteria should now match only when the start/end dates of the same element satisfy the range. On a related note, you may also be interested in the $ projection operator, to limit fornitureFuture to only the matched element(s).
I'm working on a rating system. When a user rates, $inc increments the field, and addToSet adds the user_id to make sure the user only clicks rate once. I am checking if the user_id is already in the x field before updating, but that is another query which I'd rather avoid. Can I reach this purpose without having to write another query? I mean, $addToSet only adds if there is no value like that; can I instead get affected rows? Can you suggest other queries?
Thank you!
..->update(
array("_id" => $idob),
array(
'$inc' => array($type => (int) 1),
'$addToSet' => array("x" => (int) $user_id)
)
);
Ok I see the problem.
..->update(
array("_id" => $idob),
array(
'$inc' => array($type => (int) 1),
'$addToSet' => array("x" => (int) $user_id)
)
);
The problem is that you need a conditional $inc there so that it only $incs if it does add to set.
This is not possible with a unique index since unique indexes work from the root of the document atm. Also you probably want to use the $inc as a form of pre-aggregation or what not.
One method could be:
update(
array('_id' => $idob, 'x' => array('$nin' => array($user_id))),
array(
'$inc' => array($type => 1),
'$push' => array('x' => (int)$user_id)
)
)
This will only do the update if that user_id does not already exist in x.
how do I build a find() query in cakePHP using these conditions:
Find where
MyModel.x = 1 and MyModel.y = 2 OR
MyModel.x = 1 and MyModel.y value does not exist (or is equal to empty string)
Can somebody tell me how I can go about building such find query?
I'm gonna give you some pointers, but you need to try to do this as it's very basic and it's always good to practice.
A basic find in cake is in the form of
$this->ModelName->find('all');
This in its default form does a SELECT * from model_names (convention is to have singular ModelName for plural table name - model_names)
To add conditions:
$this->ModelName->find('all', array('conditions' => array('ModelName.x' => 1));
To add AND conditions
$this->ModelName->find('all', array('conditions' => array(
'ModelName.x' => 1, 'ModelName.y' => 2
));
To add OR conditions
$this->ModelName->find('all', array('conditions' => array(
'OR' => array(
'ModelName.x' => 1, 'ModelName.y' => 2
)
));
To combine both
$this->ModelName->find('all', array('conditions' => array(
'ModelName.y is not' => null,
'OR' => array(
'ModelName.x' => 1, 'ModelName.y' => 2
)
));
// where y is not null and (x = 1 or y = 2)
http://book.cakephp.org/1.3/view/1030/Complex-Find-Conditions
(btw I'm sure there will be users giving you the exact answers, so just take my answer for your reference :) )
$this->MyModel->find('all', array('conditions' => array(
'OR' => array(
array(
'MyModel.x' => 1,
'MyModel.y' => 1
),
array(
'MyModle.x' => 1,
'OR' => array(
array('MyModel.y' => NULL),
array('MyModel.y' => '')
)
)
)
)));
$column_family->insert('row_key1', array('col_name1' => 'col_val1'));
$column_family->insert('row_key2', array('col_name2' => 'col_val2'));
$column_family->insert('row_key3', array('col_name3' => 'col_val3'));
$column_family->insert('row_key4', array('col_name4' => 'col_val4'));
The problem is mystery when the insert function does not insert value in sequence, instead it would appear in jumpping order: col_val2,col_val3,col_val1,col_val4
It bad when I could do a properly get_range() value as some have appear to insert into other partition.
How do I make the code insert orderly?
Have you tried using the batch_insert functionality?
$column_family->batch_insert(array(
'row_key1' => array('col_name1' => 'col_val1'),
'row_key2' => array('col_name2' => 'col_val2'),
'row_key3' => array('col_name3' => 'col_val3'),
'row_key4' => array('col_name4' => 'col_val4')
));