Estoy luchando en la escritura que obtiene 4 productos de cada categoría . lo que he hecho es
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', }, }, ]);modelo de documento
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;Resultado Esperado---
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 ]El código que he hecho funciona bien, pero tiene dos problemas. No completa el ID de la tienda desde el modelo de la tienda, incluso cuando intenté buscar. No ordena los productos en orden descendente (no ordena por fecha).
Hay algunas correcciones en su consulta implementada,
$sort el escenario tal como es,$group de grupos tal como está y pasa a la segunda fase$project tal como está y pasar a la tercera etapa$lookup con la colección de la tienda, pase products.shopId como localField$project para fusionar objeto de tienda en matriz de products$map para iterar el ciclo de la matriz de products$filter para iterar el ciclo de la matriz de la tienda que devuelve el producto coincidente$arrayElemAt para obtener el primer elemento del resultado filtrado anterior$mergeOjects para fusionar el objeto actual con el objeto de la shop filtrado 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 ] } } ] } } } } } ])Consulta
$setWindowFields y $rankproductCategory de producto y ordenar por fecha descendenterank <= 4 (4 productos más recientes) 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"}}}])