【问题标题】:How to get paginated/sliced data of subdocument array in mongo collection?如何在 mongo 集合中获取子文档数组的分页/切片数据?
【发布时间】:2013-08-12 01:01:45
【问题描述】:

我有一个这样的收藏:

{
"_id" : ObjectId("51f4ad560364f5490ccebe26"),
"fiTpcs" : [
    "uuid1",
    "uuid2",
    "uuid3",
    "uuid4",
    "uuid5"
],
"fiTpcsCnt" : 5
}

fiTpcs的列表很长,以后可以上百个。当我检索我的集合时,我想获得一个有限的 fiTpcs 列表,一次说 20 个,并发出单独的请求以从 fiTpcs 获取后续数据。我只是想确保当我有更多数据时查询不会变慢。有没有办法在mongodb中做到这一点?直到现在,我一直在做

db.userext.find({"_id" : ObjectId("51f4ad560364f5490ccebe26")}).pretty();

这总是让我得到完整的 fiTpcs 数组。我正在使用带有 Spring 的 java 驱动程序,使用 Spring/java 的解决方案也可以。请注意 - 如果解决方案需要 mongo 扫描整个 fiTpcs 数组,然后切片其中的一部分,它并没有真正增加任何性能优势,这不是我想要的。

【问题讨论】:

  • 在您的 Java 驱动程序中查找 Skip 和 Limit,如果它没有使用索引,您需要创建一个以使其合理有效。
  • 但是,如果你有一个巨大的数组中的所有数据,你应该看看$slice
  • Skip and Limit 在性能方面不好。检查stackoverflow.com/questions/5049992/mongodb-pagingstackoverflow.com/questions/7228169/…。我可以使用基于范围的分页,但如何对子文档执行此操作?
  • 刚刚看到另一个 question 的建议,可能在您的子文档上使用带有 $unwind 的聚合框架会起作用。
  • 您在寻找什么样的性能?您是否有测试表明一种方法明显优于另一种方法?在许多情况下,您会发现在实施之前看似低性能的东西实际上在类似生产的环境中是完全可以接受的。

标签: mongodb


【解决方案1】:

我可能无法完全理解您的问题,但似乎 $slice 是您正在寻找的机器人:

> db.page.find()
{ "_id" : ObjectId("51f4ad560364f5490ccebe26"), "fiTpcs" : [ "uuid1", "uuid2", "uuid3", "uuid4", "uuid5" ], "fiTpcsCnt" : 2 }
> db.page.find({}, {"fiTpcs" : {$slice : 3}})
{ "_id" : ObjectId("51f4ad560364f5490ccebe26"), "fiTpcs" : [ "uuid1", "uuid2", "uuid3" ], "fiTpcsCnt" : 2 }
> db.page.find({}, {"fiTpcs" : {$slice : [1,3]}})
{ "_id" : ObjectId("51f4ad560364f5490ccebe26"), "fiTpcs" : [ "uuid2", "uuid3", "uuid4" ], "fiTpcsCnt" : 2 }

【讨论】:

    【解决方案2】:

    经过几天的思考/尝试各种选择,这就是我最终所做的。我这样修改了我的文档:

    {
      "_id" : ObjectId("51f4ad560364f5490ccebe26"),
      "page" : 1,  //1 is the default
      "slug" : "some-unique-string-identifier"
      "fiTpcs" : [
        "uuid1",   //these could be long text, like a long comment/essay
        "uuid2",
        "uuid3",
        "uuid4",
        "uuid5"
      ],
      "fiTpcsCnt" : 5
    }
    

    我在 memcached 中保留了“pageCount”和“totalFiTpcsCnt”。我已设置 MAX_FITPCSCNT = 500(目前为 500,实验性)。当我创建一个 userext 类型的新文档时,我将页面值设置为 1。

    如果我必须将新对象推送到 fiTpcs 数组:

    1) 检查“totalFiTpcsCnt”是否为 500 的倍数。如果是,则使用相同的 slug 创建一个 userext 类型的新文档,fiTpcsCnt 为 0,fiTpcs 数组为空。 2) 更新最后一个userext——通过slug和“pageCount”查询,推送到fiTpcs。驱逐“pageCount”和“totalFiTpcsCnt”的缓存。

    每当我需要我的 userext 文档时,我总是只取第一页。这样我就不需要一次查询超过 500 个 fiTpcs 类型的对象,而且我仍然会在 memcached 中始终更新 totalFiTpcsCnt。

    【讨论】:

    • 我会将这个问题保留几天,看看是否有人可以提出更好的解决方案。
    • 这不是你问的。里面没有fiTpcs分页,只是拆分文档而已。
    猜你喜欢
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 2023-04-08
    • 2021-01-16
    • 1970-01-01
    • 2018-12-18
    • 2020-09-05
    • 2021-02-16
    相关资源
    最近更新 更多