首页 > 解决方案 > 将有关一个用户的所有数据存储在 mongodb 上的一个大文档中以及性能和速度如何?

问题描述

我正在创建一个项目,为用户分析网站并将所有文本放入每个页面并将其存储在 mongodb 文档中我正在考虑文档的结构,但我不知道最好的方法是什么我是 mongodb 的新手,我只是想到了 json 的这种结构。

{
 "userId": "ObjectId",
 "fullname": "Mohammad Shawahneh",
 "sites": {
   "site1.com": {
     "/page1": [
       {
         "text": "lorem ipsam",
         "score": 95
       },
       {
         "text": "ipsam lorem",
         "score": 90
       }
     ],
     "/page2": [
       {
         "text": "lorem ipsam",
         "score": 95
       }
     ]
   },
   "site2.com": {
     "/page1": [
       {
         "text": "loreem iipsam",
         "score": 80
       }
     ]
   }
 }
}

所以我想查询的数据是我想获取特定用户->站点->页面上的所有文本,例如我想像这样查询 userId(eg 1).sites.site1.com./page1。

考虑到:

  1. 该集合将包含带有 id 索引的用户文档
  2. 该集合可能有成千上万的用户
  3. 每个用户可以有很多网站
  4. 每个网站可能有数千个页面
  5. 每个页面可能有数千个文本对象
  6. 每个文本对象都可以有大文本

那么查询会很快还是大文档会影响它或者它会受到另一个方面的影响?如果它不是一个好的结构,考虑到我需要尽可能快的查询和大量数据,我应该怎么做。

抱歉,如果我遗漏了关于 NoSql 的一些明显内容,因为我对它完全陌生,并且没有找到对我的担忧有帮助的东西。

标签: mongodbmongodb-query

解决方案


当前结构在用户 ID 之外不可索引,您可以改用数组,这至少允许您按子文档字段进行查询,尽管您提到的限制也不是一个好主意,因为:

  • 每个文档的大小限制为 16MB
  • 大数组造成的碎片

您可以将每个站点的每个页面存储在不同的集合中,然后使用聚合管道从类似于关系数据库的 DB 命令中实现单个输出。

我很快将以下解决方案组合在一起,可能需要进行一些调整以更好地适应您的用例,但它至少应该可以帮助您入门。https://mongoplayground.net/p/XGztgyRIQ91

根据您期望每页有多少文本,您也可以将它们分开。

// Database layout, each key being a collection

db={
  users: [
    {
      _id: ObjectId("5fe8185bc06521a6fd8996c9"),
      fullname: "Mohammad Shawahneh",
      
    }
  ],
  sites: [
    {
      _id: ObjectId("5fe8185bc06521a6fd8996c8"),
      url: "site1.com",
      name: "Site 1"
    }
  ],
  pages: [
    {
      user: ObjectId("5fe8185bc06521a6fd8996c9"),
      site: ObjectId("5fe8185bc06521a6fd8996c8"),
      page: "/page1",
      texts: [
        {
          text: "lorem ipsam",
          score: 95
        },
        {
          text: "ipsam lorem",
          score: 90
        }
      ]
    }
  ]
}

// Aggregation Pipeline:

db.pages.aggregate([
  {
    $match: {
      user: ObjectId("5fe8185bc06521a6fd8996c9"),
      site: ObjectId("5fe8185bc06521a6fd8996c8"),
      page: "/page1"
    }
  },
  {
    $lookup: {
      from: "users",
      localField: "user",
      foreignField: "_id",
      as: "user"
    }
  },
  {
    $unwind: "$user"
  },
  {
    $lookup: {
      from: "sites",
      localField: "site",
      foreignField: "_id",
      as: "site"
    }
  },
  {
    $unwind: "$site"
  }
])

// Expected Output

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "page": "/page1",
    "site": {
      "_id": ObjectId("5fe8185bc06521a6fd8996c8"),
      "name": "Site 1",
      "url": "site1.com"
    },
    "texts": [
      {
        "score": 95,
        "text": "lorem ipsam"
      },
      {
        "score": 90,
        "text": "ipsam lorem"
      }
    ],
    "user": {
      "_id": ObjectId("5fe8185bc06521a6fd8996c9"),
      "fullname": "Mohammad Shawahneh"
    }
  }
]

可能的数组解决方案至少是可索引的,但根据上面的段落,我不推荐它。

{
    "userId": "ObjectId",
    "fullname": "Mohammad Shawahneh",
    "sites": [{
        "id": "site1.com",
        "pages": [{
                "id": "/page1",
                "texts": [{
                        "text": "lorem ipsam",
                        "score": 95
                    },
                    {
                        "text": "ipsam lorem",
                        "score": 90
                    }
                ]
            },
            {
                "id": "/page2",
                "texts": [{
                    "text": "ipsam lorem",
                    "score": 95
                }]
            }
        ]
    }]
}

推荐阅读