【问题标题】:mongodb schema design for ProductSchema and ReviewSchemaProductSchema 和 ReviewSchema 的 mongodb 模式设计
【发布时间】:2020-02-18 12:19:26
【问题描述】:

我有两个系列:产品和评论 我最初决定不在产品模式中嵌套评论,因为评论的数量可能会非常大。而且我还需要独立查询评论供管理员查看。

当用户访问产品页面时,我可以在后端服务器中“加入”该产品和相应的最近二十条评论(分页,例如每页 20 条)并将其返回给客户端。现在这是一个类似“sql”的方法,它工作得很好。

但后来我想,只嵌套最近的 20 条评论怎么样。这些嵌套审核也将存储为单独的审核文档。现在这会导致 20 次重复和更多更新。但是产品和评论的阅读量更大,这种方式可以将阅读速度降低近一半。 (而不是两个数据库请求,我们只有一个请求)

请分享您的意见。谢谢!

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    在产品集合中保存评论引用将导致每次对该文档进行新评论时更新产品文档。并且产品会有很多其他的领域,所以没有必要让它有更多的领域。

    我会建议家长参考这里。产品集合中不会有评论参考,但我们会将产品参考保留在评论集合中。当对产品进行评论时,我们只需要在评论集合中进行简单的插入即可。

    我们还需要考虑对产品进行评论的用户。所以我们需要在评论集合中保留一个用户参考。

    让我展示这些集合的一些示例文档:

    产品:

    {
        "_id" : ObjectId("5e4bdffb09d2675c3cdf8371"),
        "name" : "Product1",
        "price" : 1
    }
    

    用户:

    {
        "_id" : ObjectId("5e4bdfa809d2675c3cdf8370"),
        "username" : "User1",
    }
    

    评论:(用户 1 对 Product1 进行了评论)

    {
      "_id": ObjectId("5e4be86809d2675c3cdf8387"),
      "reviewDate": ISODate("2020-02-18T15:51:22.584+03:00"),
      "product": ObjectId("5e4bdffb09d2675c3cdf8371"),
      "user": ObjectId("5e4be85d09d2675c3cdf8386"),
      "score": 5
    }
    

    我们可以使用 mongodb 聚合框架在一个数据库访问中读取产品信息及其评论和评论的用户。所以这不是什么大问题。

    例如:Playground

    db.products.aggregate([
      {
        $match: {
          _id: ObjectId("5e4bdffb09d2675c3cdf8371")
        }
      },
      {
        $lookup: {
          from: "reviews",
          localField: "_id",
          foreignField: "product",
          as: "reviews"
        }
      },
      {
        $unwind: "$reviews"
      },
      {
        $sort: {
          "reviews.reviewDate": -1
        }
      },
      {
        $lookup: {
          from: "users",
          localField: "reviews.user",
          foreignField: "_id",
          as: "user"
        }
      },
      {
        $addFields: {
          "reviews.user": {
            $arrayElemAt: [
              "$user",
              0
            ]
          }
        }
      },
      {
        $project: {
          user: 0
        }
      },
      {
        $group: {
          _id: "$_id",
          reviews: {
            "$push": "$reviews"
          },
          "doc": {
            "$first": "$$ROOT"
          }
        }
      },
      {
        $replaceRoot: {
          newRoot: {
            $mergeObjects: [
              "$doc",
              {
                "reviews": "$reviews"
              }
            ]
          }
        }
      }
    ])
    

    这将通过以下方式给出结果:

    [
      {
        "_id": ObjectId("5e4bdffb09d2675c3cdf8371"),
        "name": "Product1",
        "price": 1,
        "reviews": [
          {
            "_id": ObjectId("5e4be83b09d2675c3cdf8381"),
            "product": ObjectId("5e4bdffb09d2675c3cdf8371"),
            "reviewDate": ISODate("2020-02-18T16:15:22.584Z"),
            "score": 2,
            "user": {
              "_id": ObjectId("5e4be83009d2675c3cdf8380"),
              "username": "User8"
            }
          },
          {
            "_id": ObjectId("5e4be09709d2675c3cdf8375"),
            "product": ObjectId("5e4bdffb09d2675c3cdf8371"),
            "reviewDate": ISODate("2020-02-18T15:02:22.584Z"),
            "score": 4,
            "user": {
              "_id": ObjectId("5e4be08b09d2675c3cdf8374"),
              "username": "User2"
            }
          },
          {
            "_id": ObjectId("5e4be84b09d2675c3cdf8383"),
            "product": ObjectId("5e4bdffb09d2675c3cdf8371"),
            "reviewDate": ISODate("2020-02-18T14:08:22.584Z"),
            "score": 3,
            "user": {
              "_id": ObjectId("5e4be84109d2675c3cdf8382"),
              "username": "User9"
            }
          },
        ...
        ]
      }
    ]
    

    这样,当您打开产品详细信息页面的 GET api 时,这将包含您需要的所有信息。

    【讨论】:

      猜你喜欢
      • 2015-06-27
      • 2015-01-26
      • 2016-03-29
      • 1970-01-01
      • 2019-02-12
      • 2018-06-09
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      相关资源
      最近更新 更多