Mongoose 查询 - groupBy 类别并获取每个类别的最后 4 项

Posted

技术标签:

【中文标题】Mongoose 查询 - groupBy 类别并获取每个类别的最后 4 项【英文标题】:Mongoose query - groupBy category and get last 4 items of each category 【发布时间】:2021-10-22 02:58:11 【问题描述】:

我正在努力编写 每个类别的 4 个产品。我所做的是

 exports.recentproducts = catchAsync(async (req, res, next) => 
     const doc = await Product.aggregate([
     $sort:  date: -1  ,
    
      $replaceRoot: 
        newRoot: 
          $mergeObjects: [ $arrayElemAt: ['$products', 0] , '$$ROOT'],
        ,
      ,
    ,
    
      $group:     
        _id: '$productCategory',
        products:  $push: '$$ROOT' ,
      ,
    ,

    
      $project: 
        // pagination for products
        products: 
          $slice: ['$products', 4],
        ,
        _id: 1,
       
      ,
    ,
    
       $lookup: 
           from: 'Shop',
           localField: 'shopId',
           foreignField: '_id',
           as: 'shop',
     ,
    ,
  ]);

文档模型

const mongoose = require('mongoose');
   var ProductSchema = mongoose.Schema(
    title: 
        type: String,
        require: [true, 'Product must have a Title!'],
      ,
      productCategory: 
        type: String,
        require: [true, 'Product must have a Category!'],
      ,
      shopId: 
        type: mongoose.Schema.ObjectId,
        ref: 'Shop',
        require: [true, 'Product must have a Shop!'],
      ,
    );
    
    var Product = mongoose.model('Product', ProductSchema);
    module.exports = Product;

预期结果---

result= [
    
        productCategory: "Graphics",
        products:[//4 products object here
           
               must populate shop data
           
       ]
    ,
    
        productCategory: "3d",
        products:[//4 products object here]
    ,
       //there are seven categories I have like that
  ]
     

我所做的代码运行良好,但有两个问题 即使我尝试了查找,它也不会从 Shop 模型中填充 shopId 它不按降序对产品进行排序(不按日期排序)

【问题讨论】:

您需要向我们展示文件和预期结果 我已经添加了更多细节,请您查看 【参考方案1】:

查询

在 MongoDB 5 中,我们可以使用 $setWindowFields$rankproductCategory分区并按日期降序排序 只保留rank <= 4(4 个最新产品) 查找店铺信息 按类别分组推送产品和店铺的所有信息

Test code here

Product.aggregate(
[$setWindowFields:
  partitionBy:"$productCategory",
   sortBy:date:-1,
   output:rank:$rank:,
 $match:rank:$lte:4,
 $lookup:
  from:"Shop",
   localField:"shopId",
   foreignField:"_id",
   as:"shop",
 $set:shop:$first:"$shop",
 $group:_id:"$productCategory", products:$push:"$$ROOT"])

【讨论】:

此代码出错。无法识别的管道阶段名称:'$setWindowFields 它需要 mongodb 5,这就是为什么我在 mongodb 5 中说我们可以这样做,我猜你有旧版本。【参考方案2】:

在您实现的查询中修复了一些问题,

$sort 舞台, $group 原样进入第二阶段 $project 原样进入第三阶段 $lookup有店铺收藏,通过products.shopIdlocalField $project 用于合并 products 数组中的商店对象 $map 迭代 products 数组的循环 $filter循环店铺数组返回匹配产品 $arrayElemAt 从上面的过滤结果中获取第一个元素 $mergeOjects 将当前对象与过滤后的shop 对象合并
const doc = await Product.aggregate([
   $sort:  date: -1  ,
  
    $group: 
      _id: "$productCategory",
      products:  $push: "$$ROOT" 
    
  ,
  
    $project: 
      products:  $slice: ["$products", 4] 
    
  ,
  
    $lookup: 
      from: "Shop",
      localField: "products.shopId",
      foreignField: "_id",
      as: "shop"
    
  ,
  
    $project: 
      products: 
        $map: 
          input: "$products",
          in: 
            $mergeObjects: [
              "$$this",
              
                shop: 
                  $arrayElemAt: [
                    
                      $filter: 
                        input: "$shop",
                        as: "s",
                        cond:  $eq: ["$$s._id", "$$this.shopId"] 
                      
                    ,
                    0
                  ]
                
              
            ]
          
        
      
    
  
])

Playground

【讨论】:

以上是关于Mongoose 查询 - groupBy 类别并获取每个类别的最后 4 项的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose 查找所有帖子并获取最热门的类别

无法在关系 nestjs/mongoose 上查询条件

laravel groupby 与数组

Mongoose 按查找字段分组

如何从mongoose查询中检索值

Pandas groupby 类别,评级,从每个类别中获得最高价值?