我是mongodb的新手,也许这是一个微不足道的问题。我有两个mongodb集合:user
和post
。用户可以创建和关注多个帖子,并按照上次修改日期列出帖子。特定帖子后可能会有大量用户,因此我不想在每个帖子文档中保留关注者列表。另一方面,一个用户可能不会关注超过几千个帖子,所以我决定在每个用户文档中保留关注帖子的目标列表。
为了能够快速列出给定用户最近修改的50个帖子,我选择保留last_updated_at
字段以及帖子objectid。
post
文档非常基础:
{
"_id" : ObjectId("5163deebe4d809d55d27e847"),
"title" : "All about music"
"comments": [...]
...
}
user
文档如下所示:
{
"_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_updated_at
添加到用户文档中posts
列表的末尾。修改帖子时(例如,在帖子中添加评论时),我会在所有关注者的用户文档中更新该帖子的last_updated_at
字段。那很重,但我不知道如何避免它。
当我想获取用户最近更新的50个帖子的列表时,我很遗憾地需要获取所有后续帖子的列表,然后在内存中按last_updated_at
排序,然后只保留前50个帖子
因此,我尝试更改实施,以便在修改帖子时对列表进行重新排序:我$push
将其添加到列表的末尾,并$pull
将其从任何位置开始。由于这是一个两步程序,因此存在竞争条件,我可能会在列表中获得两倍相同的帖子。有没有更好的方法来维护mongodb中的排序数组?
答案 0 :(得分:9)
由于您可能经常更新给定用户的最新帖子,因此您可能希望避免不必要地重写数据以维护已排序数组的开销。
更好的考虑方法是展平数据模型并使用单独的集合而不是有序数组:
(userID, postID, lastUpdated)
multi:true
和upsert:true
选项以及$set
last_updated_at为新值执行简单的update()
。find()
。如果你想维护有序数组,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") }
}
}
)
这种方法的一个好处是数组操作正在服务器上完成,但与在应用程序中对数组进行排序一样,您可能仍然需要更新文档。