【问题标题】:Select all fields from a collection, sorted by lowest field value and "grouped" by distinct field?从集合中选择所有字段,按最低字段值排序并按不同字段“分组”?
【发布时间】:2019-06-02 22:46:21
【问题描述】:

我有一个集合 scores 包含以下字段

┬────────┬───────┬──────────┐
│ player │ score │   mode   │
┼────────┼───────┼──────────┤
│  'A'   │   7   │  'easy'  │
│  'A'   │  11   │ 'medium' │
│  'A'   │  12   │  'hard'  │
│  'B'   │   9   │  'hard'  │
│  'B'   │  10   │  'easy'  │
│  'B'   │  10   │ 'medium' │
│  'C'   │   6   │ 'medium' │
│  'C'   │   9   │  'easy'  │
│  'C'   │  13   │  'hard'  │
┴────────┴───────┴──────────┘

我想选择所有最小的分数by player,所以预期的结果是:

┬────────┬───────┬──────────┐
│ player │ score │   mode   │
┼────────┼───────┼──────────┤
│  'A'   │   7   │  'easy'  │
│  'B'   │   9   │  'hard'  │
│  'C'   │   6   │ 'medium' │
┴────────┴───────┴──────────┘

另外,我想保留文档的原始结构,以便将预期结果加载为 mongoose 对象。

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    您可以使用聚合框架:

    1. $sort收藏就播放器然后得分
    2. 使用$group舞台按玩家分组,并在每个组中获取$first条目
    3. $project 到必要的输出格式
    4. 播放器上的可选$sort

    例如,这是基于您的示例的集合:

    > db.test.find()
    { "_id": 2, "player": "A", "score": 12, "mode": "hard" }
    { "_id": 0, "player": "A", "score": 7, "mode": "easy" }
    { "_id": 1, "player": "A", "score": 11, "mode": "medium" }
    { "_id": 3, "player": "B", "score": 9, "mode": "hard" }
    { "_id": 4, "player": "B", "score": 10, "mode": "easy" }
    { "_id": 5, "player": "B", "score": 10, "mode": "medium" }
    { "_id": 6, "player": "C", "score": 6, "mode": "medium" }
    { "_id": 7, "player": "C", "score": 9, "mode": "easy" }
    { "_id": 8, "player": "C", "score": 13, "mode": "hard" }
    

    使用上述工作流程进行聚合:

    db.test.aggregate([
    
      {$sort: {player: 1, score: 1}},
    
      {$group: { _id: '$player', 
                 player: {$first:'$player'},
                 score: {$first:'$score'}, 
                 mode: {$first:'$mode'} }},
    
      {$project: { _id: 0 }},
    
      {$sort: {player: 1}}
    
    ])
    

    输出是:

    { "player": "A", "score": 7, "mode": "easy" }
    { "player": "B", "score": 9, "mode": "hard" }
    { "player": "C", "score": 6, "mode": "medium" }
    

    如果您的收藏量很大,请确保您有一个index,其规格为{player: 1, score: 1}

    【讨论】:

    • 谢谢!只有最后一个问题:我的收藏有大约 30 个字段,我需要填充所有字段。有没有什么办法不用在$project对象中一一写入就可以全部投影出来?
    • 不幸的是,据我所知没有捷径可走。很可能所有 30 个字段都需要出现在 $group 和 $project 阶段。
    • 我收回了。我编辑了 $group 以便它也捕获玩家,所以在 $project 阶段你可以删除 _id 字段。但是,您仍然需要在 $group 阶段拥有所有必填字段。我认为这是无法避免的。
    猜你喜欢
    • 2014-06-23
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多