【问题标题】:Aggregating and comparing scores of teams using mongodb使用 mongodb 聚合和比较团队的分数
【发布时间】:2014-06-28 10:26:59
【问题描述】:

我刚刚开始使用 mongodb,并且一直在阅读有关聚合的文档,但仍在努力将 sql 语句的等效知识与 mongo 中使用的方法联系起来。

我有这些数据:

{
         "_id" : ObjectId("53ac7bce4eaf6de4d5601c19"),
         "uid" : ObjectId("53ac7bb84eaf6de4d5601c15"),
         "mid" : ObjectId("53ab27504eaf6de4d5601be4"),
         "score" : 1
},{
        "_id" : ObjectId("53ac7bce4eaf6de4d5601c1a"),
        "uid" : ObjectId("53ac7bb84eaf6de4d5601c16"),
        "mid" : ObjectId("53ab27504eaf6de4d5601be4"),
        "score" : 5
}
...

我正在努力得到这个结果:

{
        "uid" : ObjectId("53ac7bb84eaf6de4d5601c15"),
        "uid_2" : ObjectId("53ac7bb84eaf6de4d5601c16"),
        "mid" : ObjectId("53ab27504eaf6de4d5601be4"),
        "score" : 1,
        "score_2" : 5,
        "difference" : 4
}
...

我将每个 uid 与围绕单个 mid 的每个其他 uid 进行比较,并计算它们的分数差异(不能是负差异,只有正差异)。

我遇到的大多数示例都不太符合我的要求,希望一些 mongo 大师可以帮助我。谢谢!

【问题讨论】:

  • 您的样本数据缺少一些信息来说明哪些“两个”团队相互匹配。除了说它无效之外,我不会评论结果的无效结构。但实际上,如果您想要“配对”而不仅仅是一次要求两个团队,您需要一个公共字段来“配对”它们。
  • 对不起,你是对的,这两个团队实际上是 uid 的。我正在使数据在语义上更正确,但现在,这就是我所拥有的。我确实希望将每个 uid 与其他所有 uid 进行比较。
  • 更新了数据,使其更有意义。共同点是中间。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

如上所述,我认为您的数据建模有点偏离,因为您需要一些东西来“配对”“匹配”。我在这里有一个“简化”的案例:

{ 
    "_id" : ObjectId("53ae9da2e24682cac4215e0c"), 
    "match" : ObjectId("53ae9d78e24682cac4215e0b"), 
    "score" : 1 
}
{
    "_id" : ObjectId("53ae9da5e24682cac4215e0d"),
    "match" : ObjectId("53ae9d78e24682cac4215e0b"),
    "score" : 5
}
{ 
    "_id" : ObjectId("53aea6cde24682cac4215e15"),
    "match" : ObjectId("53aea6c1e24682cac4215e14"), 
    "score" : 2
}
{
    "_id" : ObjectId("53aea6e4e24682cac4215e16"),
    "match" : ObjectId("53aea6c1e24682cac4215e14"),
    "score" : 1
}
{ 
    "_id" : ObjectId("53aea6eae24682cac4215e18"), 
    "match" : ObjectId("53aea6e6e24682cac4215e17"), 
    "score" : 2
}
{ 
    "_id" : ObjectId("53aea6ece24682cac4215e19"),
    "match" : ObjectId("53aea6e6e24682cac4215e17"),
    "score" : 2
}

这基本上代表的是“三”不同比赛中“六”支球队的得分。

鉴于此,我对结果的看法是这样的:

db.matches.aggregate([

    // Group on matches and find the "min" and "max" score
    { "$group": {
        "_id": "$match",
        "teams": {
            "$push": {
               "_id": "$_id",
               "score": "$score"
            }
        },
        "minScore": { "$min": "$score" },
        "maxScore": { "$max": "$score" }
    }},

    // Unwind the "teams" array created
    { "$unwind": "$teams" },

    // Compare scores for "win", "loss" or "draw"
    { "$group": {
        "_id": "$_id",
        "win": {
           "$min": { "$cond": [
               { "$and": [
                   { "$eq": [ "$teams.score", "$maxScore" ] },
                   { "$gt": [ "$teams.score", "$minScore" ] }
               ]},
               "$teams",
               false
           ]}
        },
        "loss": {
           "$min": { "$cond": [
               { "$and": [
                   { "$eq": [ "$teams.score", "$minScore" ] },
                   { "$lt": [ "$teams.score", "$maxScore" ] }
               ]},
               "$teams",
               false
           ]}
        },
        "draw": {
            "$push": { "$cond": [
               { "$eq": [ "$minScore", "$maxScore" ] },
               "$teams",
               false
            ]}
        },
        "difference": { 
            "$max": { "$subtract": [ "$maxScore", "$minScore" ] }
        }
    }},

    // Just fix up those "draw" results with a [false,false] array
    { "$project": {
        "win": 1,
        "loss": 1,
        "draw": { "$cond": [ 
             { "$gt": [
                 { "$size": { "$setDifference": [ "$draw", [false] ] } },
                 0
             ]},
             "$draw",
             false
        ]},
        "difference": 1
    }}
])

这会给你一个很好的结果:

{
    "_id" : ObjectId("53ae9d78e24682cac4215e0b"),
    "win" : {
            "_id" : ObjectId("53ae9da5e24682cac4215e0d"),
            "score" : 5
    },
    "loss" : {
            "_id" : ObjectId("53ae9da2e24682cac4215e0c"),
            "score" : 1
    },
    "draw" : false,
    "difference" : 4
}
{
    "_id" : ObjectId("53aea6c1e24682cac4215e14"),
    "win" : {
            "_id" : ObjectId("53aea6cde24682cac4215e15"),
            "score" : 2
    },
    "loss" : {
            "_id" : ObjectId("53aea6e4e24682cac4215e16"),
            "score" : 1
    },
    "draw" : false,
    "difference" : 1
}
{
    "_id" : ObjectId("53aea6e6e24682cac4215e17"),
    "win" : false,
    "loss" : false,
    "draw" : [
            {
                    "_id" : ObjectId("53aea6eae24682cac4215e18"),
                    "score" : 2
            },
            {
                    "_id" : ObjectId("53aea6ece24682cac4215e19"),
                    "score" : 2
            }
    ],
    "difference" : 0
}

这本质上是每次“比赛”的结果,并确定获胜者和失败者之间的“差异”,同时确定哪支球队“获胜”或“失败”。那里的最后阶段使用一些仅在 MongoDB 2.6 中引入的运算符,但如果您没有该版本可用,那真的没有必要。或者,如果您愿意,您实际上仍然可以通过使用$unwind 和其他一些处理来执行相同的操作。

【讨论】:

  • 这太棒了!在你这样表达之后,我现在明白你的意思了。真是太感谢你了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2021-04-02
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多