首页 > 解决方案 > 根据项目在另一个集合中被引用的次数对项目进行排序

问题描述

我有一个项目集合,每个项目都有一个类型(水果、蔬菜等)和一个 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
            }
        ]
    }
]

标签: mongodbmongoosemongodb-queryaggregate

解决方案


这可能会帮助你,

  • $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游乐场


推荐阅读