Mongodb $ in没有返回正确的序列

时间:2014-04-21 07:13:19

标签: php mongodb

我有查询

  $cursor = $collection->find(array('id' =>array('$in'=>array(4,3,2,1))), array('name'));
         foreach($cursor as $fild)
                {
               echo  $fild['name'].'<br>';
                }

返回

    Need for speed: Most Wanted
    Pro Evolution Soccer 2014
    Fifa 2014
    Star Craft 2

如果我改变数组中的顺序,如(3,2,4,1)。 返回

Need for speed: Most Wanted
Pro Evolution Soccer 2014
Fifa 2014
Star Craft 2

必须返回

Fifa 2014
Pro Evolution Soccer 2014
Star Craft 2
Need for speed: Most Wanted

我做错了什么?

1 个答案:

答案 0 :(得分:0)

基本上,这不是$in运算符的工作方式,对于MongoDB或任何数据库中的任何等效形式。因此,您放入参数的顺序不会保留在您的结果中,因为您似乎期望它们。

但是,为了实现这一目标,您可以采取几种方法。第一个是通过聚合管道的一些创造性使用:

var selections = [ 4, 2, 3, 1 ];

db.collection.aggregate([
   // $match is like a standard "find" query
   { "$match": {
       "id": { "$in": selections  }
   }},

   // Project your field(s) and a sorting field
   { "$project": {
       "_id": 0,
       "name": 1,
       "order": { "$cond": [
          { "$eq": [ "$id", 4 ] },
          1,
          { "$cond": [
              { "$eq": [ "$id", 2 ] },
              2,
              { "$cond": [
                  { "$eq": [ "$id", 3 ] },
                  3,
                  4
              ]}
          ]}
       ]}
   }},

   // Sort on the generated field
   { "$sort": { "order": } }
])

因此,使用$cond运算符(ternary operator),您正在评估id的当前值,以确定要分配的排序顺序。当然,您实际上会使用类似于shown here的方法在代码中为此条件生成管道内容。

当然,如果这看起来有点过于复杂,即使您最好这样做,那么您可以使用mapReduce以类似的方式解决问题。但由于这在解释器中使用JavaScript代码并且不使用aggregate之类的本机代码,因此运行速度会变慢:

var selections = [ 4, 2, 3, 1 ];

db.collection.mapReduce(
    function() {
        emit(
            selections.indexOf( this.id ),
            this.name
        );            
    },
    function(){},
    { 
        "query": { "id": { "$in": selections } },
        "scope": { "selections": selections },
        "out": { "inline": 1 }
    }
)

这种方式利用了mapReduce如何对映射器中发出的键值进行排序,因此通过按照数组中的索引值进行定位可以保持排序顺序。

因此,您可以使用几种方法来“动态”生成排序顺序,类似于数组中参数的顺序。