首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在聚合Mongodb中使用$getfield从具有条件的根文档中获取字段

如何在聚合Mongodb中使用$getfield从具有条件的根文档中获取字段
EN

Stack Overflow用户
提问于 2022-09-26 12:55:29
回答 2查看 99关注 0票数 0

我开始在MongoDB中学习聚合。我有一个简单的文档,如下所示,其中有两个字段,nameexamScoresexamScores是一个包含乘数文档的array

代码语言:javascript
运行
复制
{ _id: ObjectId("633199db009be219a43ae426"),
  name: 'Max',
  examScores: 
   [ { difficulty: 4, score: 57.9 },
     { difficulty: 6, score: 62.1 },
     { difficulty: 3, score: 88.5 } ] }
{ _id: ObjectId("633199db009be219a43ae427"),
  name: 'Manu',
  examScores: 
   [ { difficulty: 7, score: 52.1 },
     { difficulty: 2, score: 74.3 },
     { difficulty: 5, score: 53.1 } ] }

现在,我使用$group/$max查询每个人的最大分数,如下所示:

代码语言:javascript
运行
复制
db.test.aggregate([
    {$unwind: "$examScores"},
    {$group: {_id: {name: "$name"}, maxScore: {$max: "$examScores.score"}}}
])
{ _id: { name: 'Max' }, maxScore: 88.5 }
{ _id: { name: 'Manu' }, maxScore: 74.3 }

但是,我希望结果还包含与nameexamScores.score对应的name字段,如下所示:

代码语言:javascript
运行
复制
{ _id: { name: 'Max' }, difficulty: 3, maxScore: 88.5 }
{ _id: { name: 'Manu' }, difficulty: 2, maxScore: 74.3 }

我知道我可以使用$sort + $group$first来实现这个目标。但是我想使用$getFieldany other methodsROOT Doc获取数据。

我的想法是使用$project$getFieldROOT doc (或$unwind version of ROOT doc)获得difficulty field,条件是ROOT.name = Aggregate.nameRoot.examScores.score = Aggregate.maxScore

看起来会是这样的:

代码语言:javascript
运行
复制
{$project: 
          {name: 1, 
          maxScore: 1, 
          difficulty: 
                        {$getField: {
                         field: "$examScores.difficulty"
                         input: "$$ROOT.$unwind() with condition/filter"}
                        }
           }
}

我想知道这在MongoDB中是否可行?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-09-26 13:29:46

解决方案1

  1. $unwind
  2. $group -集团由name.您需要$push$$ROOT文档添加到data数组中。
  3. $project -通过将difficultymaxScore匹配,从过滤后的data数组的第一项中获取examScores.difficulty的值,从而设置examScores.score字段。
代码语言:javascript
运行
复制
db.collection.aggregate([
  {
    $unwind: "$examScores"
  },
  {
    $group: {
      _id: {
        name: "$name"
      },
      maxScore: {
        $max: "$examScores.score"
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $project: {
      _id: 0,
      name: "$_id.name",
      maxScore: 1,
      difficulty: {
        $getField: {
          field: "difficulty",
          input: {
            $getField: {
              field: "examScores",
              input: {
                $first: {
                  $filter: {
                    input: "$data",
                    cond: {
                      $eq: [
                        "$$this.examScores.score",
                        "$maxScore"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
])

演示解决方案1@ Mongo游乐场

$rank 解决方案2:

  1. $unwind
  2. $rank -按分区nameexamScores.score降序排序。
  3. $match -使用{ rank: 1 }过滤文档。
  4. $unset -删除rank字段。
代码语言:javascript
运行
复制
db.collection.aggregate([
  {
    $unwind: "$examScores"
  },
  {
    $setWindowFields: {
      partitionBy: "$name",
      sortBy: {
        "examScores.score": -1
      },
      output: {
        rank: {
          $rank: {}
        }
      }
    }
  },
  {
    $match: {
      rank: 1
    }
  },
  {
    $unset: "rank"
  }
])

演示解决方案2@ Mongo游乐场

意见:我要说的是:

  1. $sortexamScores.score降序
  2. $group按名称,取第一个文档

就容易多了。

票数 1
EN

Stack Overflow用户

发布于 2022-09-27 00:03:12

不需要使用$unwind,然后再通过$group重新构建文档来实现您想要的结果。我建议完全避免那样做。

相反,考虑使用数组表达式运算符内联处理数组。根据您正在寻找的版本和确切结果,这里有两个可能值得考虑的起点。特别是,$maxN算子$sortArray算子可能对这一特定问题感兴趣。

您可以通过运行$addFields聚合来查看它们的输出操场在这里来了解这两个操作符所做的事情。

以这些作为起点,真正取决于您如何使管道输出达到所需的结果。下面是一个与您在问题(游乐场)中描述的输出相当匹配的示例:

代码语言:javascript
运行
复制
db.collection.aggregate([
  {
    "$addFields": {
      "relevantEntry": {
        $first: {
          $sortArray: {
            input: "$examScores",
            sortBy: {
              "score": -1
            }
          }
        }
      }
    },
    
  },
  {
    "$project": {
      _id: 0,
      name: 1,
      difficulty: "$relevantEntry.difficulty",
      maxScore: "$relevantEntry.score"
    }
  }
])

产生的结果:

代码语言:javascript
运行
复制
[
  {
    "difficulty": 3,
    "maxScore": 88.5,
    "name": "Max"
  },
  {
    "difficulty": 2,
    "maxScore": 74.3,
    "name": "Manu"
  }
]

同样值得注意的是,如果存在重复,这种特定的方法不会做任何特别的事情。如果在这方面还需要更多的东西,您可以考虑使用$filter

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73854490

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档