How to fetch all the fields in mongodb aggregate function? - mongodb

I have wriiten below lines of code
public function BasicSearchStudents($input)
{
$this->page =1;
$page=(int)$this->page;
$skip=($page - 1)*12;
$param = preg_replace('!\s+!', ' ', $input);
$arg = trim($param);
$output= $this->db->studentTbl->aggregate(
array(
array(
'$project' => array(
'fullname' => array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
'firstmiddle' => array('$concat' => array('$first_name', ' ', '$middle_name')),
'firstlast' => array('$concat' => array('$first_name', ' ', '$last_name')),
'first_name' => 1,
'middle_name' =>1,
'last_name' =>1,
'roll_no' =>1,
'registration_temp_perm_no' =>1,
'email' =>1,
'guardian_name' =>1,
'phone1' =>1,
'phone2' =>1,
'dob' =>1,
'student_id' =>1,
'is_active' =>1,
'has_finished' =>1
)
),
array(
'$match' =>
array('$or' =>
array(
array("fullname" => new MongoRegex("/$arg/i")),
array("first_name" => new MongoRegex("/$arg/i")),
array("middle_name" => new MongoRegex("/$arg/i")),
array("last_name" => new MongoRegex("/$arg/i")),
array("firstmiddle" => new MongoRegex("/$arg/i")),
array("firstlast" => new MongoRegex("/$arg/i")),
array("registration_temp_perm_no" => new MongoRegex("/$arg/i")),
array("roll_no" => new MongoRegex("/$arg/i")),
array("email" => new MongoRegex("/$arg/i")),
array("guardian_name" => new MongoRegex("/$arg/i")),
array("phone1" => new MongoRegex("/$arg/i")),
array("dob" => new MongoRegex("/$arg/i"))
)
)
),
array(
'studentresult' => array(
'$push' => '$$ROOT'
)
),
array('$limit' => 22),
array('$skip' =>$skip),
)
);
$cursor = $output["studentresult"];
}
I am trying to fetch all the fields used in student collection in by using root after match operation. It throws error "Uncaught exception 'MongoResultException' with message 'localhost:27017: Unrecognized pipeline stage name: 'result''".
Please help me.

Related

Internal server error on delete - Contao

I'm new to contao . I created a backend custom module . The listing of records is looking fine.But When I trying to delete or copy the record the system returns internal server error.And also can't edit pre-saved records.Screenshots are attached below.Please help me.
// List
'list' => array
(
'sorting' => array
(
'mode' => 1,
'fields' => array('title'),
'flag' => 1,
'panelLayout' => 'filter;search,limit'
),
'label' => array
(
'fields' => array('title', 'teaser'),
'format' => '%s <span style="color:#b3b3b3;padding-left:3px;">[%s]</span>'
),
'global_operations' => array
(
'all' => array
(
'label' => &$GLOBALS['TL_LANG']['MSC']['all'],
'href' => 'act=select',
'class' => 'header_edit_all',
'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
)
),
'operations' => array
(
'editheader' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_solutions']['editheader'],
'href' => 'act=edit',
'icon' => 'edit.gif'
),
'copy' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_solutions']['copy'],
'href' => 'act=copy',
'icon' => 'copy.gif'
),
'delete' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_solutions']['delete'],
'href' => 'act=delete',
'icon' => 'delete.gif',
'attributes' => 'onclick="if(!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"'
),
'show' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_solutions']['show'],
'href' => 'act=show',
'icon' => 'show.gif'
)
)
),

Sort with results matching condition on top

I have written mongodb aggregation query in php like below lines of code.
$orrollno= array('$or' => array(array("student.roll_no" => new MongoRegex("/$arg/i"))));
$orlastname= array('$or' => array(array("student.last_name" => new MongoRegex("/$arg/i"))));
$oremail= array('$or' => array(array("student.email" => new MongoRegex("/$arg/i"))));
$orguardian= array('$or' => array(array("student.guardian_name" => new MongoRegex("/$arg/i"))));
$orphone= array('$or' => array(array("student.phone1" => new MongoRegex("/$arg/i"))));
$orfullname= array('$or' => array(array("fullname" => new MongoRegex("/$arg/i"))));
$orfirstmiddle= array('$or' => array(array("firstmiddle" => new MongoRegex("/$arg/i"))));
$orfirstlast= array('$or' => array(array("firstlast" => new MongoRegex("/$arg/i"))));
$query = array( '$or' => array($orrollno,$orlastname,$oremail,$orguardian,$orphone,$orfullname,$orfirstmiddle,$orfirstlast));
$outputTotalResults= $this->db->studentTbl->aggregate(
array(
array(
'$project' => array(
'fullname' => array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
'firstmiddle' => array('$concat' => array('$first_name', ' ', '$middle_name')),
'firstlast' => array('$concat' => array('$first_name', ' ', '$last_name')),
'student' => '$$ROOT'
)
),
array(
'$match' => $query
),
)
);
I am trying to sort the results which comes from $match => $query.
For e.g $arg contains "William David" then results should first contain the records with names Willian David and then the rest of the results.
Any help shall be greatly appreciated!!!
Based on ur suggestion I have now tried the below
$outputTotalResults= $this->db->studentTbl->aggregate(
array(
array(
'$project' => array(
'fullname' => array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
'firstmiddle' => array('$concat' => array('$first_name', ' ', '$middle_name')),
'firstlast' => array('$concat' => array('$first_name', ' ', '$last_name')),
'student' => '$$ROOT',
'weight' => array(
'$cond' => array(
array(
'$or' => array(
array('$eq' => array('$fullname' => $arg )),
array('$eq' => array('$firstmiddle' => $arg)),
array('$eq' => array('$firstlast' => $arg)),
)
),
10,
0
)
),
array(
'$sort' => array( 'weight'=> -1 )
),
array(
'$match' => $query
),
)
)
)
);
What you want to achieve here is a "weighted sort", where you essentially want to calculate a field based on conditions and then apply a $sort pipeline stage to that result.
The general case is to apply $cond with a logical condition and either return a value or not, possibly for more than one condition in a cascading way.
Ideally with MongoDB 3.4 and above, use $addFields:
array(
array(
'$addFields' => array(
'weight' => array(
'$cond => array(
array(
'$and' => array(
array( '$eq' => array( '$first_name', 'Willam' ) )
array( '$eq' => array( '$last_name', 'David' ) )
)
),
10,
0
)
)
)
),
array(
'$sort' => array( 'weight'=> -1 )
)
)
Or in prior versions where you cannot simply "append" a new field to the existing document structure you use $project, either specifying each field you want or altering the structure returning under one property via $$ROOT:
array(
array(
'$project' => array(
'first_name' => 1,
'last_name' => 1,
'weight' => array(
'$cond => array(
array(
'$and' => array(
array( '$eq' => array( '$first_name', 'Willam' ) )
array( '$eq' => array( '$last_name', 'David' ) )
)
),
10,
0
)
)
)
),
array(
'$sort' => array( 'weight'=> -1 )
)
)
So in that simple case, whenever the "both" conditions (via $and) are met, the weight property is assigned a value of 10, otherwise it gets a 0. The subsequent sort on the weight property is in "descending" order, so all the 10 values where the condition matched will be on "top", whilst all other results will come after all the matches.
This is how you would structure for your exact implementation. First you $match your query conditions as this reduces the overall documents to process and this is the only time an aggregation pipeline can actually use an index.
Then you $project the field with the comparisons for whether the match phrase was in the preferred fields, and finally $sort on that calculated field.
array(
array( '$match' => $query ),
array(
'$addFields' => array(
'weight' => array(
'$cond => array(
array(
'$or' => array(
array(
'$eq' => array(
array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
$arg
)
),
array(
'$eq' => array(
array('$concat' => array('$first_name', ' ', '$middle_name')),
$arg
)
),
array(
'$eq' => array(
array('$concat' => array('$first_name', ' ', '$last_name')),
$arg
)
)
)
),
10,
0
)
)
)
),
array(
'$sort' => array( 'weight'=> -1 )
)
)
So always $match first or otherwise use a pipeline stage that is going to use an index and "optimize" your result. Then manipulate and remember that you cannot use calculated fields for comparison in a "single" $project phase. If you really need it then you either duplicate the calculations or do the calculations in one stage and then compare on the values in the next stage.
Honestly though, once you go to these lengths you are basically reproducing what a text search, in which you can:
Spread the index across all the fields you want to search in. This eliminates the massive $or condition into a simple query operation.
Specify a weighting on the particular fields where the match would be more important.
The only case where a "text search" would not be the best solution is if the fields you want "more weight on" change on a regular basis. Since text indexes have "set" values for the weighting and you can have only one per collection, then you cannot easily change the combination of fields to assign more weight to. With the aggregation process shown, its fairly trivial to change around the fields and assignment of weight.

Unrecognized pipeline stage name: '$addFields''

I have written mongo db query like
$outputTotalResults= $this->db->studentTbl->aggregate(
array(
array(
'$addFields' => array(
'weight' => array(
'$cond' => array(
array(
'$or' => array(
array(
'$eq' => array(
array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
$arg
)
),
array(
'$eq' => array(
array('$concat' => array('$first_name', ' ', '$middle_name')),
$arg
)
),
array(
'$eq' => array(
array('$concat' => array('$first_name', ' ', '$last_name')),
$arg
)
)
)
),
10,
0
)
)
)
),
array(
'$sort' => array( 'weight'=> -1 )
)
)
);
I am trying to sort the students. The above code is throwing error "Unrecognized pipeline stage name: '$addFields''"
Please help me !!!
Please check your mongodb version. This feature is not available on 3.2, it's been added in v3.4. Upgrade the db then.

How to merge query in wordpress with different arguments

$all = array(
'post_type' => array("pwpd_poll","pwpd_infog"),
'posts_per_page' => wp_is_mobile() ? 3 : 7,
'orderby' => 'post_date',
'order' => 'DESC'
);
$news = array(
'post_type' =>array('pwpd_news'),
'meta_query' => $meta_query_par,
'date_query'=>array(
array(
'year' => $today['year'],
'month' => $today['mon'],
'day' => $today['mday'],
)
)
);
the problem is the $news output is always in the end of the loop the "orderby" doesnt seem to be working and also the "posts_per_page" is not exact in the output.

cakephp form validation password comparision

I have a function to reset a password.
At the point where I have to compare the password and the password_confirm field, I get a strange behavior:
My form
echo $this->Form->hidden('tkn', array('value' => $tkn));
echo $this->Form->hidden('uid', array('value' => $uid));
echo $this->Form->input('password',array('type' => 'password', 'name' => 'data[Appuser][password]'));
echo $this->Form->input('password_confirm',array('type' => 'password', 'name' => 'data[Appuser][password_confirm]'));
My model validation:
var $validate = array(
'password' => array(
'rule' => array('minLength', '6'),
'message' => '{password} minLength 6!'
),
'password_confirm' => array(
'rule' => array('equaltofield','password'),
'message' => '{password_confirm} not equal!'
),
);
function equaltofield($val1, $val2){
return $this->data[$this->alias][key($val1)] == $this->data[$this->alias][$val2];
}
My Controller:
if($this->Appuser->save($this->data)){
$this->Session->setFlash(__('Password has been updated'));
}else{
debug($this->Appuser->invalidFields());
}
Now:
When I submit an empty form I get the following returned from the invalidFields()
array(
'password' => '*****',
'password_confirm' => array(
(int) 0 => '{password_confirm} not equal!',
(int) 1 => '{password_confirm} not equal!'
)
)
Question 1: Why do I not get the message, that the password has not its minlength?
Question 2: Why do I get the second message twice for comparing the password?
When typing in 2 different password with min length, I get this again:
array(
'password_confirm' => array(
(int) 0 => '{password_confirm} not equal!',
(int) 1 => '{password_confirm} not equal!'
)
)
When debug($this->data) I also get this (if that helps somehow)
array(
'Api' => array(
'tkn' => '6837d241bf1076c3c55a95abbcfafa04dc19a33c',
'uid' => '1'
),
'Appuser' => array(
'password' => '*****',
'password_confirm' => 'asdfgh'
)
)
Any ideas regarding my two questions above?
Thanks in advance!!
Try this
var $validate = array(
'password' => array(
'rule' => array('minLength', '6'),
'message' => '{password} minLength 6!'
),
'password_confirm' => array(
'rule' => 'equaltofield',
'message' => '{password_confirm} not equal!'
),
);
function equaltofield($data){
return $this->data[$this->alias]['password'] == $this->data[$this->alias]['password_confirm'];
}