【问题标题】:Mongoose query - groupBy category and get last 4 items of each categoryMongoose 查询 - groupBy 类别并获取每个类别的最后 4 项
【发布时间】: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 它不按降序对产品进行排序(不按日期排序)

【问题讨论】:

  • 您需要向我们展示文件和预期结果
  • 我已经添加了更多细节,请您查看

标签: javascript node.js mongodb mongoose mongodb-query


【解决方案1】:

查询

  • 在 MongoDB 5 中,我们可以使用 $setWindowFields$rank
  • productCategory分区并按日期降序排序
  • 只保留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

【讨论】:

    猜你喜欢
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    • 2021-08-24
    • 2017-09-27
    • 2021-01-02
    相关资源
    最近更新 更多