MongoDB PHP聚合数据&x2B;计数+;哪里
我用PHP/MYsql创建了一个平台,现在正在迁移到mongo 我对mysql的旧查询: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 有多个这样的文件,我需要找到召
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"
}
}
}}
];
演练
- 匹配文档:这主要是使用
完成的,因为您要在数组元素中查找“多个”条件。对于数组元素上的“单个”条件,可以使用: 但是对于需要使用的“一个”条件以外的任何条件,否则该语句真正要问的是“这个是否匹配数组中的某个东西?”,而这并不包含元素中的“all”。因此,即使and组合本身实际上也是“两个”条件,因此需要$elemMatch
:$elemMatch
这里还注意到,从“1到6包括在内”表示“大于或等于”,反之亦然,表示“小于”条件"players": { "$elemMatch": { "position": { "$gte": 1, "$lte": 6 } } }
- “预筛选”:这里需要注意的是,最终目标是通过数组中的一个元素进行“分组”,即
。这意味着最终你需要修改内容才能做到这一点 但是,“定位”
管道操作的成本将相当高,因为它会“分解”阵列并为每个阵列成员创建一个新文档进行处理。由于您只需要“某些”实际匹配条件的成员,因此最好在“反规范化此内容”之前“从数组中删除”任何不匹配的内容 MongoDB3.2提供了一个很好的方法来解决这个问题。通过“过滤”数组的内容,使其只匹配特定条件集的元素,它的执行与命名完全相同 在聚合管道阶段,我们使用它的运算符的“逻辑变体”,如和。根据条件匹配的位置,它们返回一个$unwind
值。在数组中,也可以使用成员字段将它们引用为“”中的别名参数的“点符号”,该参数指向当前处理的成员 这里还有另一个“逻辑运算符”,它执行相同的true/false
响应。因此,这意味着必须满足其参数数组中的“所有”参数,才能返回true/false
。对于本身,在true
中计算的“cond”
真/假
中的确定是否返回数组元素 对于不具有
运算符的MongoDB 2.6,相同的运算符用组合表示,简单地说,$filter
查看每个元素,并在“$map
将作为当前数组成员返回。如果它是”中应用表达式。在这种情况下,我们使用which作为“三元”运算符来计算“if/then/else”形式 因此这里的
返回“if”
中的表达式,那么“true
,false
中的表达式返回,在本例中,我们返回else
(PHPfalse
)的值 由于所有成员实际上都是由false
的结果返回的,因此我们通过应用$map
操作符模拟$setDifference
。这将与数组的成员进行比较,并从结果中有效地“删除”元素返回为$filter
的所有成员。因此,对于像您这样的不同数组成员,结果“集”(是“唯一”元素的“集”)只包含那些条件为false
且返回非false值的元素true
- “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)