MongoDB 按结果限制组

问题描述 投票:0回答:1

我的 mongo DB 有一个具有以下结构的文档:

{'vname':'x', 'pname': 'xyz', 'price': '10000'}

我想获取与

pname='xy'
匹配的所有文档,然后按
vname
进行分组,并将每个
vname
的结果限制为 4。

pipeline = [
    {
        '$facet': {
            'v1': [
                {
                    '$match': {'vname': 'v1'}
                },
                {
                    '$sort': {'price': 1}
                },
                {
                    '$limit': 4
                }
            ],
            'v2': [
                {
                    '$match': {'vname': 'v2'}
                },
                {
                    '$sort': {'price': 1}
                },
                {
                    '$limit': 4
                }
            ]
        }
    }
]

docs = Pinfo.objects(pname__icontains='xy').aggregate(pipeline=pipeline)

我看到的另一种方法是为每个

vname

多次运行过滤器查询
docs = Pinfo.objects.filter(Q(pname__icontains='xy')&Q(vname__exact='v1')).limit(4)

还有其他方法可以达到同样的效果吗? 使用聚合和管道方法是更好的方法吗?

mongodb aggregation-framework mongoengine
1个回答
2
投票

你可以尝试一下,

  • $match
    pname
    状况
  • $sort
    pname
    升序(可选)
  • $group
    通过
    vname
    并将根对象推入项目中并创建数组
  • $project
    显示必填字段并使用
    $slice
  • 获取 4 个对象
db.collection.aggregate([
  { $match: { pname: "xy" } },
  { $sort: { pname: 1 } },
  {
    $group: {
      _id: "$vname",
      items: { $push: "$$ROOT" }
    }
  },
  {
    $project: {
      _id: 0,
      vname: "$_id",
      items: { $slice: ["$items", 4] }
    }
  }
])

游乐场


如果您想要根中的所有对象,那么您可以在上面的管道之后添加下面的管道,

  • $unwind
    将项目数组解构为对象
  • $replaceRoot
    替换根目录中的项目对象
  { $unwind: "$items" },
  { $replaceRoot: { newRoot: "$items" } }

游乐场


MongoDB 5.2 的更多选项,在

$topN
阶段使用
$group
运算符,

db.collection.aggregate([
  { $match: { pname: "xy" } },
  {
    $group: {
      _id: "$vname",
      items: {
        $topN: {
          output: {
            pname: "$pname",
            price: "$price"
          },
          sortBy: { price: 1 },
          n: 4
        }
      }
    }
  }
])

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.