在没有竞争条件的情况下,如何使用mongodb实现有序数组?
我是mongodb的新手,也许这是一个微不足道的问题。我有两个mongodb集合:在没有竞争条件的情况下,如何使用mongodb实现有序数组?,mongodb,optimization,Mongodb,Optimization,我是mongodb的新手,也许这是一个微不足道的问题。我有两个mongodb集合:user和post。用户可以创建和跟踪多篇文章,文章按上次修改日期排序。可能会有大量用户关注某个特定的帖子,所以我不想在每个帖子文档中保留关注者列表。另一方面,一个用户关注的帖子可能不会超过几千篇,因此我决定在每个用户文档中保留关注帖子的objectid列表 为了能够快速列出给定用户最近修改的50篇文章,我选择将last\u updated\u与post objectid一起保存在字段中 post文档相当基本: {
user
和post
。用户可以创建和跟踪多篇文章,文章按上次修改日期排序。可能会有大量用户关注某个特定的帖子,所以我不想在每个帖子文档中保留关注者列表。另一方面,一个用户关注的帖子可能不会超过几千篇,因此我决定在每个用户文档中保留关注帖子的objectid列表
为了能够快速列出给定用户最近修改的50篇文章,我选择将last\u updated\u与post objectid一起保存在字段中
post
文档相当基本:
{
"_id" : ObjectId("5163deebe4d809d55d27e847"),
"title" : "All about music"
"comments": [...]
...
}
用户
文档如下所示:
{
"_id": ObjectId("5163deebe4d809d55d27e846"),
"posts": [{
"post": ObjectId("5163deebe4d809d55d27e847"),
"last_updated_at": ISODate("2013-04-09T11:27:07.184Z")
}, {
"post": ObjectId("5163deebe4d809d55d27e847"),
"last_updated_at": ISODate("2013-04-09T11:27:07.187Z")
}]
...
}
当用户创建或跟踪帖子时,我可以简单地将帖子的$push
ObjectId
和上次更新时间
推到用户文档中帖子
列表的末尾。修改帖子时(例如,在帖子中添加评论时),我会在所有关注者的用户文档中更新该帖子的last\u updated\u at
字段。那很重,但我不知道如何避免
当我想为一个用户获取50篇最近更新的文章的列表时,不幸的是,我需要获取所有后续文章的列表,然后在内存中按last\u updated\u at
排序,然后只保留前50篇文章
因此,我尝试更改实现,以便在修改帖子时对列表重新排序:I$push
将其推到列表的末尾,以及$pull
将其从任何位置拖到列表的末尾。因为这是一个两步程序,所以有一个竞争条件,我可能会在列表中得到两次相同的帖子。在mongodb中没有更好的方法来维护排序数组吗?数据模型调整
由于您可能会经常更新给定用户的最新帖子,因此您可能希望避免为了维护排序数组而不必要地重写数据的开销
一个更好的考虑方法是扁平化数据模型并使用单独的集合而不是有序数组:
- 使用更新后的帖子流创建一个单独的集合:
(userID、postID、lastUpdated)
- 更新帖子后,您可以使用
multi:true
和upsert:true
选项和$set
将上次更新的帖子设置为新值进行简单操作
- 要检索给定用户ID的最近50篇更新文章,您可以使用排序和限制选项执行普通的
find()
- 要自动清理“旧”文档,您甚至可以为此集合设置一个新的集合,以便在一定天数后从活动流中删除更新
在MongoDB 2.4中推送到固定大小和排序的数组
如果您确实希望维护有序阵列,MongoDB 2.4添加了两个与此用例相关的有用特性:
- 能够推送到固定大小的阵列
- 能够推送到按嵌入文档字段排序的数组
因此,您可以实现将50个项目按上次更新日期降序排列的固定大小数组:
db.user.update(
// Criteria
{ _id: ObjectId("5163deebe4d809d55d27e846") },
// Update
{ $push: {
posts: {
// Push one or more updates onto the posts array
$each: [
{
"post": ObjectId("5163deebe4d809d55d27e847"),
"last_updated_at": ISODate()
}
],
// Slice to max of 50 items
$slice:-50,
// Sorted by last_updated_at desc
$sort: {'last_updated_at': -1}
}
}}
)
$push
将按排序顺序更新列表,而$slice
将列表修剪为前50项。由于帖子不是唯一的,您仍然需要先从列表中$pull
原始帖子,例如:
db.user.update(
// Criteria
{ _id: ObjectId("5163deebe4d809d55d27e846") },
// Update
{
$pull: {
posts: { post: ObjectId("5163deebe4d809d55d27e847") }
}
}
)
这种方法的一个好处是在服务器上进行数组操作,但与在应用程序中对数组进行排序一样,您可能仍然需要更新更多的文档。+1这很好,谢谢。不过,只有一个问题:修改帖子时,我需要在用户的posts
列表中找到它,并在字段中更新它的last\u updated\u。这会自动对列表重新排序吗?如果不会,我想我应该从列表中删除它,然后立即再次添加它(反之亦然)。将有一个小的延迟,帖子
列表将不一致,不是吗?@MiniQuark:考虑到需要$pull/$push和更新频率,重新考虑了方法。更有效的方法是展平数据模型,避免维护有序阵列。。已相应更新;-)。这是很好的建议,非常感谢。如果我能+2,我会。:-)