【问题标题】:MongoDB multiple/nested aggregationsMongoDB 多重/嵌套聚合
【发布时间】:2021-12-02 08:29:30
【问题描述】:

我有这些收藏:

users

{
  _id: "userId1",
  // ...
  tracks: ["trackId1", "trackId2"],
};

tracks

{
  _id: "trackId1",
  // ...
  creatorId: "userId1",
  categoryId: "categoryId1"
}

categories

{
  _id: "categoryId1",
  // ...
  tracks: ["trackId1", "trackId15", "trackId20"],
};

通过使用以下代码,我可以通过 ID 获取曲目并添加创建者

tracks.aggregate([
        {
          $match: { _id: ObjectId(trackId) },
        },
        {
          $lookup: {
            let: { userId: { $toObjectId: "$creatorId" } },
            from: "users",
            pipeline: [{ $match: { $expr: { $eq: ["$_id", "$$userId"] } } }],
            as: "creator",
          },
        },
        { $limit: 1 },
      ])
      .toArray();

回复:

"track": {
    "_id": "trackId1",
    // ...
    "categoryId": "categoryId1",
    "creatorId": "userId1",
    "creator": {
        "_id": "userId1",
        // ...
        "tracks": [
            "trackId5",
            "trackId10",
            "trackId65"
        ]
    }
}

但我正在苦苦挣扎的是,我希望 creator.tracks 也通过其 ID 聚合返回曲目(例如,直到最后 5 个),并从 categoryId 获取最后 5 个曲目

预期结果:

"track": {
    "_id": "trackId1",
    // ...
    "categoryId": "categoryId1",
    "creatorId": "userId1",
    "creator": {
        "_id": "userId1",
        "tracks": [
            {
                "_id": "trackId5",
                // the rest object without the creator
            },
            {
                "_id": "trackId10",
                // the rest object without the creator
            },
            {
                "_id": "trackId65",
                // the rest object without the creator
            },
        ]
    },
    // without trackId1 which is the one that is being viewed
    "relatedTracks": [
        {
            "_id": "trackId15",
            // the rest object without the creator
        },
        {
            "_id": "trackId20",
            // the rest object without the creator
        },
    ]
}

我将不胜感激任何解释/帮助,以了解什么是最好的,并且仍然保持良好的性能

【问题讨论】:

    标签: mongodb aggregate relational-database aggregation


    【解决方案1】:

    查询

    • 从轨道开始
    • 加入用户使用trackId获取创作者的所有曲目 (创作者轨迹)
    • 使用categoryId加入类别,获取该类别的所有曲目(相关曲目)
    • 从相关曲目中删除创作者的曲目
    • 使用$slice(创作者轨道和相关轨道)从两者中取出最后 5 个

    *我添加了 2 个额外的查找来获取轨道的所有信息,它的空数组因为我没有足够的数据(我只有 trackId1),所有数据都可以使用

    Test code here

    db.tracks.aggregate([
      {
        "$match": {
          "_id": "trackId1"
        }
      },
      {
        "$lookup": {
          "from": "users",
          "localField": "creatorId",
          "foreignField": "_id",
          "as": "creator-tracks"
        }
      },
      {
        "$set": {
          "creator-tracks": {
            "$arrayElemAt": [
              "$creator-tracks.tracks",
              0
            ]
          }
        }
      },
      {
        "$lookup": {
          "from": "categories",
          "localField": "categoryId",
          "foreignField": "_id",
          "as": "related-tracks"
        }
      },
      {
        "$set": {
          "related-tracks": {
            "$arrayElemAt": [
              "$related-tracks.tracks",
              0
            ]
          }
        }
      },
      {
        "$set": {
          "related-tracks": {
            "$filter": {
              "input": "$related-tracks",
              "cond": {
                "$not": [
                  {
                    "$in": [
                      "$$this",
                      "$creator-tracks"
                    ]
                  }
                ]
              }
            }
          }
        }
      },
      {
        "$set": {
          "creator-tracks": {
            "$slice": [
              {
                "$filter": {
                  "input": "$creator-tracks",
                  "cond": {
                    "$ne": [
                      "$$this",
                      "$_id"
                    ]
                  }
                }
              },
              -5
            ]
          }
        }
      },
      {
        "$set": {
          "related-tracks": {
            "$slice": [
              "$related-tracks",
              -5
            ]
          }
        }
      },
      {
        "$lookup": {
          "from": "tracks",
          "localField": "creator-tracks",
          "foreignField": "_id",
          "as": "creator-tracks-all-info"
        }
      },
      {
        "$lookup": {
          "from": "tracks",
          "localField": "related-tracks",
          "foreignField": "_id",
          "as": "related-tracks-all-info"
        }
      }
    ])
    

    【讨论】:

    • 我更新了答案,我认为这就是你想要的
    • 好的,我想你想要每个曲目的所有曲目信息,我更新为在你完成后进行 2 次查找,以获得这 5 + 5 个曲目的额外信息。我们没有轨道 15/20 等的数据,所以它是空的,但如果我们有完整的数据,它将起作用
    • 在我使用的数据中,我没有音轨 2、音轨 3 等,您只提供了 1 条音轨的数据,在上次更新中,我从创建者音轨中删除了音轨(我又添加了一个过滤器)。现在创作者曲目除了 trackID(我们开始的地方)之外的所有曲目,类别除了创作者曲目之外的所有曲目
    • 您可以进行最后 2 次查找,并在结果中放置它们的名称,它们将被替换,而不是 creator-tracks-info 放置 creator-tracks,而不是相关轨道信息放置相关轨道,它们将被替换。您也可以 $unset 它们,无需将这些数据发送给客户端。例如this
    • 完全符合我的预期,您为我省去了很多挫折 :) 感谢您的宝贵时间和帮助!
    猜你喜欢
    • 2021-03-13
    • 2018-11-17
    • 2017-07-26
    • 2017-07-16
    • 2019-07-20
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 2018-07-06
    相关资源
    最近更新 更多