根据项目在另一个集合中被引用的次数对项目进行排序

问题描述

我有一个项目集合,每个项目都有一个类型(水果、蔬菜等)和一个 ID:

type: 'Fruit',_id: '0'

type: 'vegetable',_id: '1'

type: 'Fruit',_id: '2'

然后我有一个购买的集合,每个购买都引用一个项目:

item_id: '2'

item_id: '1'

item_id: '0'

item_id: '2'

现在我可以使用以下代码获取最畅销的商品:

buySchema.aggregate([
    { $group: { _id: "$item_id",numFills: { $sum: 1 } } },{ $sort: { numFills: -1 } }
]).limit(10).exec(function (err,top) {
    if (err) return res.status(400).send('error');
    return res.status(200).send(top);
});

代码输出以下 json:

[
  {
    "_id": "2","numFills": 2
  },{
    "_id": "0","numFills": 1
  },{
    "_id": "1","numFills": 1
  }
]

我现在想要的是每种类型的顶级列表(一个用于水果,另一个用于蔬菜等),如下所示:

[
    {
        "type": "Fruits","items": [
            {
                "_id": "2","numFills": 2
            },{
                "_id": "0","numFills": 1
            }
        ]
    },{
        "type": "vegetables",items: [
            {
                "_id": "1","numFills": 1
            }
        ]
    }
]

解决方法

这可能对你有帮助,

  • $lookup 加入两个集合。我用过 uncorelated lookup
  • $unwind 来解构数组。因为我们无法对数组进行排序
  • $sort 按降序排序
  • $group 通过 type
  • 重建数组

脚本在这里

db.items.aggregate([
  {
    "$lookup": {
      "from": "buys","let": { iId: "$_id" },"pipeline": [
        {
          $match: {
            $expr: { $eq: [ "$item_id","$$iId" ] }
          }
        },{
          $group: {
            _id: "$item_id",numFills: { $sum: 1 }
          }
        }
      ],"as": "joinBuys"
    }
  },{ "$unwind": "$joinBuys" },{
    $sort: { "joinBuys.numFills": -1 }
  },{
    $group: {
      _id: "$type",items: { $push: "$joinBuys" }
    }
  }
])

工作Mongo playground