在顶部排序结果匹配条件

时间:2017-05-18 05:27:22

标签: mongodb mongodb-query aggregation-framework mongodb-php

我在php中编写了mongodb聚合查询,如下面的代码行。

         $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
                       ),
                    )
                 );

我正在尝试对来自$ match =>的结果进行排序$查询。 例如,$ arg包含" William David"然后结果应首先包含名称为Willian David的记录,然后包含其余结果。

非常感谢任何帮助!!!

根据你的建议我现在尝试了以下

            $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
                             ),
                         )
                      )
                   )
               );

1 个答案:

答案 0 :(得分:0)

您希望在此处实现的是“加权排序”,您基本上希望根据条件计算字段,然后将$sort管道阶段应用于该结果。

一般情况是将$cond应用于逻辑条件并返回一个值或不返回值,可能以级联方式对多个条件进行返回。

理想情况下,使用MongoDB 3.4及更高版本,请使用$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 )
  )
)

或者在之前的版本中,您不能简单地将新字段“追加”到您使用$project的现有文档结构,指定所需的每个字段或通过$$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 )
  )
)

因此,在这种简单的情况下,只要满足“两个”条件(通过$and),就会为weight属性赋值10,否则会得到0 1}}。 weight属性的后续排序是“降序”,因此条件匹配的所有10值都将位于“顶部”,而所有其他结果将在所有匹配之后。< / p>

这是您为确切实现而构建的方式。首先,$match您的查询条件会减少要处理的整体文档,这是聚合管道实际上可以使用索引的唯一时间。

然后你$project字段,比较匹配短语是否在首选字段中,最后是$sort在该计算字段上。

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 )
  )
)

首先总是 $match或者使用将要使用索引并“优化”结果的管道阶段。然后操纵并记住,您不能在“单个”$project阶段使用计算字段进行比较。如果你真的需要它,那么你要么重复计算,要么在一个阶段进行计算,然后比较下一阶段的值。

老实说,一旦你达到这些长度,你基本上会再现一个text search,你可以在其中:

  1. 在您要搜索的所有字段中展开索引。这样就可以将大量$or条件转移到简单的查询操作中。

  2. 指定匹配更重要的特定字段的加权。

  3. “文本搜索”不是最佳解决方案的唯一情况是,您希望“更多权重”的字段会定期更改。由于文本索引具有“设置”加权值,并且每个集合只能一个,因此您无法轻松更改字段组合以分配更多权重。通过显示聚合过程,可以非常轻松地改变字段和权重分配。