Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB PHP聚合数据&x2B;计数+;哪里_Php_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

MongoDB PHP聚合数据&x2B;计数+;哪里

MongoDB PHP聚合数据&x2B;计数+;哪里,php,mongodb,mongodb-query,aggregation-framework,Php,Mongodb,Mongodb Query,Aggregation Framework,我用PHP/MYsql创建了一个平台,现在正在迁移到mongo 我对mysql的旧查询: select sum(game_won) as game_won,count(id) as total,position from games_player_stats where position < 6 and position > 0 and user_id = :pa_id group by position order by total desc 有多个这样的文件,我需要找到召

我用PHP/MYsql创建了一个平台,现在正在迁移到mongo

我对mysql的旧查询:

select sum(game_won) as game_won,count(id) as total,position
from games_player_stats 
where position < 6 and position > 0 and user_id = :pa_id 
group by position 
order by total desc
有多个这样的文件,我需要找到召唤师编号123456有多少次处于2号位置或任何其他1-6号位置,他在该位置赢了多少次

索引需要在区域和召唤者id上可查询

结果会是这样的

 {
   "positions" : 
         [
           { "position" : 1,
             "total" : 123,
             "won" : 65
           },
           { "position" : 2,
             "total" : 37,
             "won" : 10
           }
         ]
   }

我需要使用Map/Reduce吗?

这方面的最佳结果是通过MongoDB聚合框架获得的。它与mapReduce的不同之处在于,所有操作都是使用“本机编码运算符”执行的,而不是mapReduce使用的JavaScript计算

这意味着“更快”,而且意义重大。更不用说,您所寻找的结果中也有某些部分实际上支持“多组”概念,该概念本质上可用于“管道”操作,否则使用mapReduce将是一个相当丑陋的累加器

聚合管道格式 最佳方法将根据您可用的MongoDB“服务器”版本而有所不同

理想情况下,使用MongoDB 3.2可以在处理之前“预过滤”数组内容:

对于MongoDB 2.6.x版本,仍然使用“预过滤”,但使用和:

对于使用MongoDB 2.2聚合框架的早期版本,在“the
$unwind
”之后加上“
$match
”的“post filter”:

var pipeline = [
    // Match documents with array members matching conditions
    { "$match": {
        "players": {
            "$elemMatch": {
                "summoner_id": 123456,
                "position": { "$gte": 1, "$lte": 6  }
            }
        }
    }},

    { "$unwind": "$players" },

    // Post filter the denormalized content
    { "$match": {
        "players.summoner_id": 123456,
        "players.position": { "$gte": 1, "$lte": 6 }
    }},

    // Group on the inner "position"
    { "$group": {
        "_id": "$players.position",
        "total": { "$sum": 1 },
        "won": { "$sum": "$players.won" }
    }},

    // Optionally Sort by position since $group is not ordered
    { "$sort": { "total": -1 } },

    // Optionally $group to a single document response with an array
    { "$group": {
        "_id": null,
        "positions": {
            "$push": {
                "position": "$_id",
                "total": "$total",
                "won": "$won"
            }
        }
    }}
];
演练
  • 匹配文档:这主要是使用
    $elemMatch
    完成的,因为您要在数组元素中查找“多个”条件。对于数组元素上的“单个”条件,可以使用:

    但是对于需要使用的“一个”条件以外的任何条件,否则该语句真正要问的是“这个是否匹配数组中的某个东西?”,而这并不包含元素中的“all”。因此,即使and组合本身实际上也是“两个”条件,因此需要
    $elemMatch

    "players": {
        "$elemMatch": {
            "position": { "$gte": 1, "$lte": 6 }
        }
    }
    
    这里还注意到,从“1到6包括在内”表示“大于或等于”,反之亦然,表示“小于”条件

-

  • “预筛选”:这里需要注意的是,最终目标是通过数组中的一个元素进行“分组”,即
    “定位”
    。这意味着最终你需要修改内容才能做到这一点

    但是,
    $unwind
    管道操作的成本将相当高,因为它会“分解”阵列并为每个阵列成员创建一个新文档进行处理。由于您只需要“某些”实际匹配条件的成员,因此最好在“反规范化此内容”之前“从数组中删除”任何不匹配的内容

    MongoDB3.2提供了一个很好的方法来解决这个问题。通过“过滤”数组的内容,使其只匹配特定条件集的元素,它的执行与命名完全相同

    在聚合管道阶段,我们使用它的运算符的“逻辑变体”,如和。根据条件匹配的位置,它们返回一个
    true/false
    值。在数组中,也可以使用成员字段将它们引用为“”中的别名参数的“点符号”,该参数指向当前处理的成员

    这里还有另一个“逻辑运算符”,它执行相同的
    true/false
    响应。因此,这意味着必须满足其参数数组中的“所有”参数,才能返回
    true
    。对于本身,在
    “cond”
    中计算的
    真/假
    确定是否返回数组元素

    对于不具有
    $filter
    运算符的MongoDB 2.6,相同的运算符用组合表示,简单地说,
    $map
    查看每个元素,并在“
    中的
    ”中应用表达式。在这种情况下,我们使用which作为“三元”运算符来计算“if/then/else”形式

    因此这里的
    “if”
    返回
    true
    中的表达式,那么“
    将作为当前数组成员返回。如果它是
    false
    else
    中的表达式返回,在本例中,我们返回
    false
    (PHP
    false
    )的值

    由于所有成员实际上都是由
    $map
    的结果返回的,因此我们通过应用
    $setDifference
    操作符模拟
    $filter
    。这将与数组的成员进行比较,并从结果中有效地“删除”元素返回为
    false
    的所有成员。因此,对于像您这样的不同数组成员,结果“集”(是“唯一”元素的“集”)只包含那些条件为
    true
    且返回非false值的元素

  • “Post”过滤:MongoDB 2.6以下的服务器版本必须采用的另一种方法是“Post”过滤阵列内容。由于这些版本中没有允许在
    $unwind
    之前对数组内容执行此类操作的运算符,因此在处理
    $unwind
    之后,将另一个
    $match
    应用于内容的简单过程如下:

    { "$match": {
        "players.summoner_id": 123456,
        "players.position": { "$gte": 1, "$lte": 6 }
    }}
    
    这里使用“点表示法”,因为每个数组元素现在实际上是它自己的文档,除了查看指定路径上的条件之外,没有其他可以比较的

    这并不理想,因为当您处理
    $unwind
    时,所有与条件不匹配的元素仍然存在。这最终意味着“需要处理更多的文档”,并带来双重成本:

  • 必须为每个成员创建一个新文档,尽管它不符合条件

  • var pipeline = [
        // Match documents with array members matching conditions
        { "$match": {
            "players": {
                "$elemMatch": {
                    "summoner_id": 123456,
                    "position": { "$gte": 1, "$lte": 6  }
                }
            }
        }},
    
        { "$unwind": "$players" },
    
        // Post filter the denormalized content
        { "$match": {
            "players.summoner_id": 123456,
            "players.position": { "$gte": 1, "$lte": 6 }
        }},
    
        // Group on the inner "position"
        { "$group": {
            "_id": "$players.position",
            "total": { "$sum": 1 },
            "won": { "$sum": "$players.won" }
        }},
    
        // Optionally Sort by position since $group is not ordered
        { "$sort": { "total": -1 } },
    
        // Optionally $group to a single document response with an array
        { "$group": {
            "_id": null,
            "positions": {
                "$push": {
                    "position": "$_id",
                    "total": "$total",
                    "won": "$won"
                }
            }
        }}
    ];
    
    "players.summoner_id": 12345
    
    "players": {
        "$elemMatch": {
            "position": { "$gte": 1, "$lte": 6 }
        }
    }
    
    { "$match": {
        "players.summoner_id": 123456,
        "players.position": { "$gte": 1, "$lte": 6 }
    }}
    
        "total": { "$sum": 1 },
        "won": { "$sum": "$players.won" }
    
    pipeline = array(
        array(
            '$match' => array(
                'players' => array(
                    '$elemMatch' => array(
                        'summoner_id' => 123456,
                        'position' => array( '$gte' => 0, '$lte' => 6 )
                    )
                )
            )
        ),
        array(
            '$project' => array(
                '$filter' => array(
                    'input' => '$players',
                    'as' => 'player',
                    'cond' => (
                        '$and' => array(
                            array( '$eq' => array( '$$player.summoner_id' => 123456 ) ),
                            array( '$gte' => array( '$$player.position' => 1 ) ),
                            array( '$lte' => array( '$$player.position' => 6 ) )
                        )
                    )
                )
            )
        ),
        array( '$unwind' => '$players' ),
        array(
            '$group' => array(
                '_id' => '$players.position',
                'total' => array( '$sum' => 1 ),
                'won' => array( '$sum' => '$players.won' )
            )
        ),
        array( '$sort' => array( 'total' => -1 ) ),
        array(
            '$group' => array(
                '_id' => NULL,
                'positions' => array(
                    '$push' => array(
                        'position' => '$_id',
                        'total' => '$total',
                        'won' => '$won'
                    )
                )
            )
        )
    )
    
    $result = $collection->aggregate($pipeline);
    
    echo json_encode($pipeline, JSON_PRETTY_PRINT)