Unrecognized pipeline stage name: '$addFields'' - mongodb

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.

Related

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.

How to fetch all the fields in mongodb aggregate function?

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.

RealURL error: wrong "L" parameter value

RealURL gives this error.
My site has only one language, and I have not added any website language in root page.
I tried with config.linkVars = L and config.linkVars = L(0-5) in the setup with no effect.
RealURL Config is auto-generated:
<?php
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'] = array(
'_DEFAULT' => array(
'init' => array(
'appendMissingSlash' => 'ifNotFile,redirect',
'emptyUrlReturnValue' => '/'
),
'pagePath' => array(
'rootpage_id' => '1'
),
'fileName' => array(
'defaultToHTMLsuffixOnPrev' => 0,
'acceptHTMLsuffix' => 1,
'index' => array(
'print' => array(
'keyValues' => array(
'type' => 98
)
)
)
),
'postVarSets' => array(
'_DEFAULT' => array(
'news' => array(
0 => array(
'GETvar' => 'tx_news_pi1[news]',
'lookUpTable' => array(
'table' => 'tx_news_domain_model_news',
'id_field' => 'uid',
'alias_field' => 'title',
'useUniqueCache' => 1,
'useUniqueCache_conf' => array(
'strtolower' => 1,
'spaceCharacter' => '-'
)
)
)
)
)
)
)
);
I think thats a RealURL 2.1.7 problem.
I downgrade to RealURL 2.1.5 and then it works.
EDIT:
Now i add page.theme.language.languageValue = 0 to my template constants
See => https://github.com/dmitryd/typo3-realurl/issues/407
A quick fix for 2.1.7 can be a strict assignment of the configured "uid" integer values
linkVars = L(0-1)
… did the job for me. Instead of L(0-3)

Get rid of extensionname in realurl

I try to change my generated url from http://www.example.com/page/extensionname/MyArticleNumber/ to http://www.example.com/page/MyArticleNumber/ using Realurl 1.12.8 and TYPO3 6.2.27.
My realurl_conf.php:
'postVarSets' => array(
'_DEFAULT' => array(
'extensionname' => array(
array(
'GETvar' => 'extensionname_plugin[article]',
'lookUpTable' => array(
'table' => 'tx_extensionname_domain_model_article',
'id_field' => 'uid',
'alias_field' => 'CONCAT(short_title, \'-\', juq)',
'addWhereClause' => ' AND NOT deleted',
'useUniqueCache' => 1,
'useUniqueCache_conf' => array(
'spaceCharacter' => '-',
),
),
),
),
),
What and and where do I have to edit to solve this problem?
Thank you in advance.
If you use your extension at one specific page you can use 'fixedPostVars'
'fixedPostVars' => array(
# extension configuration
'extensionname' => array(
array(
'GETvar' => 'extensionname_plugin[article]',
'lookUpTable' => array(
'table' => 'tx_extensionname_domain_model_article',
'id_field' => 'uid',
'alias_field' => 'CONCAT(short_title, \'-\', juq)',
'addWhereClause' => ' AND NOT deleted',
'useUniqueCache' => 1,
'useUniqueCache_conf' => array(
'spaceCharacter' => '-',
),
),
),
),
# PID for extension configurations
'99' => 'extensionname',
),
I have make use of the encodeSpURL_postProc and decodeSpURL_preProc functions of realUrl.
The following code have I added to my realurl_conf.php file:
<?php
$GLOBALS['realURLEncodeSpURLArray'] = array(
'url/by/realurl/' => 'new/url/',
'page/extensionname/' => 'page/'
);
function user_encodeSpURL_postProc(&$params, &$ref)
{
$params['URL'] = str_replace(array_keys($GLOBALS['realURLEncodeSpURLArray']), array_values($GLOBALS['realURLEncodeSpURLArray']), $params['URL']);
}
function user_decodeSpURL_preProc(&$params, &$ref)
{
$params['URL'] = str_replace(array_values($GLOBALS['realURLEncodeSpURLArray']), array_keys($GLOBALS['realURLEncodeSpURLArray']), $params['URL']);
}
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'] = array(
'encodeSpURL_postProc' => array('user_encodeSpURL_postProc'),
'decodeSpURL_preProc' => array('user_decodeSpURL_preProc'),
'_DEFAULT' => array(
...
);
Please ensure that the new/url/should be unique so that there is no conflict.
By example: If you want to map txnews you got an url like mynewspage/details/txnews/article you should replace mynewspage/details/txnews/ with mynewspage/details/. Do not replace txnews/ with /!

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.