在mongodb中做到这一点的最佳方法?

时间:2019-02-25 14:56:20

标签: mongodb aggregate

db.post

{user:'50001', content:...,},
{user:'50002', content:...,},
{user:'50003', content:...,},
{user:'50001', content:...,},
{user:'50002', content:...,},

db.catagory

{user:'50001', type:'public',...}
{user:'50002', type:'vip',...}
{user:'50003', type:'public',...}

我想要的是为用户发布type:public

我可以这样做:

publicUsers = db.catagory.distinct(user, {type:'public'})
db.post.find({user: {$in: publicUsers }}).sort({_id:-1})

或汇总使用查找。

并输出

{user:'50001', content:...,},
{user:'50003', content:...,},
{user:'50001', content:...,},

还有其他更好的方法可以更快地做到这一点吗?


考虑到大量请求的情况,我是否应该创建一个新的数据库,例如post_public来查找?

2 个答案:

答案 0 :(得分:0)

聚合管道是您最好的选择。它非常适用于此类情况。

另一个编辑

好的,这是我最好的解决方案,但是Mongo设置了一些limitations

  • 首先,对未索引字段的排序操作不能使用超过100MB的RAM。

  • 第二,在这种情况下更有意义,Mongo将单个文档的大小设置为16MB。假设您希望将帖子发布为单个数组,则在不对输出施加限制的情况下,大型数据集可以通过 。如果您决定不希望所有单个数组中的帖子,则通过删除管道的最后三个阶段($ group,$ addFields和$ project),结果将为排序后的帖子每个都在自己的文档中。如果您选择这种方式,则需要手动限制文档的数量,以获取所需的 n 个帖子。海事组织,你应该这样做。后三个阶段增加了额外的处理负担,但对输出几乎没有实际的好处。唯一的区别是迭代嵌套数组与迭代根数组。

db.categories.aggregate([
  {$project: {
    user: 1,
    type: 1
  }}, 
  {$match: {
    type: "public"
  }}, 
  {$lookup: {
    from: 'posts',
    localField: 'user',
    foreignField: 'user',
    as: 'userPosts'
  }}, 
  {$unwind: {
    path: "$userPosts",
    preserveNullAndEmptyArrays: false
  }}, 
  {$sort: {
    "userPosts.posted": -1,
  }}, 
  {$group: {
    _id: "public",
    posts: {
      $push: "$userPosts"
    }
  }}, 
  {$addFields: {
    "latestPosts": {
      $slice: ["$posts", 5]
    }
  }}, 
  {$project: {
    posts: 0
  }}
]);

您将像这样访问结果帖子:

.then(result => {
  let latestPosts = result[0].latestPosts;
});

编辑

我建立了一个模拟数据库,并提出了以下解决方案:

db.categories.aggregate([{
    $project: {
        _id: 0,
        user: 1,
        type: 1,
    }
}, {
    $match: {
        type: "public"
    }
}, {
    $group: {
        _id: {
            $concat: ["$user", "-", "$type"]
        },
        user: {
            $first: "$user"
        },
        type: {
            $first: "$type"
        }
    }
}, {
    $sort: {
        user: -1
    }
}, {
    $limit: 10
}, {
    $lookup: {
        from: 'posts',
        localField: 'user',
        foreignField: 'user',
        as: 'userPosts'
    }
}]);

结果将是一个对象数组,代表每个唯一的用户类型组合,并在$ match过滤器中指定类型。该对象将包含一个由该用户发布的所有帖子的子数组。所有用户都将按降序排序,并且限制为十个。

如果您只需要一个运算符就可以从类别中获得不同的值:

db.categories.aggregate([{$project: {
  _id: 0,
  user: 1,
  type: 1
}}, {$group: {
  _id: {$concat: ["$user","-","$type"]},
  user: {$first: "$user"},
  type: {$first: "$type"}
}}]);

目标是首先过滤掉具有非公共类型的用户,使它们不会出现在结果中,然后将属于该用户的帖子加入一个名为“ user_posts”的新字段,然后对所有用户进行排序升序。我不知道您的数据库的整个结构,因此我的具体示例可能不是最合适的,但这将是一个很好的起点。


编辑

其他一些提高大量数据性能的方法:

  1. 通过分段查询。假设您要显示分页的用户帖子。然后,您只需要查询帖子以获取当前正在查看的页面。您也可以通过预提取以下几页来减少任何明显的加载时间。

  2. 使用“虚拟”列表。这将在一个长列表中显示每个帖子,但仅获取当前正在查看或即将被查看的特定大小的块。与第一个分页示例类似。如果您熟悉Android开发中的RecyclerView,就是这样。

  3. 重组帖子在数据库中的存储方式。如果Mongo在查找特定用户或类型的帖子时不需要遍历太多不相关的数据,这将是一个更快的操作。解决方案是存储嵌套在共同祖先下方的帖子,例如其海报或视图类型。这确实意味着您可能在文档之间分散了重复的条目。这是no-SQL数据库固有的缺点之一。您将需要找到一种解决方案来处理同步分布在整个数据库中的文档。

  4. 在用于对数组进行排序的文档字段上创建新索引。索引可帮助Mongo在内部组织文档以提高搜索效率。

  5. 运行一次繁重的查询,然后$out-搜索结果。这样,您可以以比简单缓存更持久的方式存储昂贵操作的结果。

  6. 数字5的一种变体是将大型排序操作的结果输出$,然后继续在现在排序的集合的末尾插入 new 条目。

答案 1 :(得分:0)

最后,我这样做。

db.post.aggregate([
    {$match:{
        uid:{$in: db.catagory.distinct('id',{type:'public'})}  # directly write here
        _id:{$lt: ObjectId("5c6d5494b9f43f020d4122a0")}        # for turn the page
    }},
    {$sort:{_id:-1}},  # sort by post _id
    {$limit:20}        # page size
])

比查找或其他方法更快。