显然,您认为将这些嵌入到“列表”文档中是一个好主意,以便您的附加使用模式能够正确地适用于此处提供的案例。考虑到这一点,没有理由抛弃它。
不过,需要澄清的是,您似乎想要的结构类似于这样:
{
"_id": "sdf3f",
"likedBy": [
{ "userId": "12ac", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "as3vd", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "sadf3", "date": ISODate("2014-04-09T07:30:47.091Z") }
],
"dislikedBy": [
{ "userId": "asdf", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "sdsdf", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "asdfas", "date": ISODate("2014-04-09T07:30:47.091Z") }
],
"active": true
}
除了有一个小问题,一切都很好。由于这个内容在两个数组字段中,您将无法在这两个字段上创建索引。这是一个限制,只能在复合索引中包含一个数组类型的字段(或多键)。
因此,为了解决第一个查询无法使用索引的明显问题,您应该像这样进行结构化:
{
"_id": "sdf3f",
"votes": [
{
"userId": "12ac",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "as3vd",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "sadf3",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "asdf",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "sdsdf",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "asdfas",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
}
],
"active": true
}
这允许创建一个涵盖此表单的索引:
db.post.ensureIndex({
"active": 1,
"votes.userId": 1,
"votes.date": 1,
"votes.type": 1
})
实际上,你可能需要一些索引来适应你的使用模式,但关键是现在你可以使用索引。
针对第一个情况,你可以使用以下查询形式:
db.post.find({ "active": true, "votes.userId": { "$ne": "12ac" } })
考虑到每个用户显然不可能同时有喜欢和不喜欢两个选项,这一点很有道理。按照该索引的顺序,至少可以使用"active"来进行过滤,因为你的否定条件需要扫描其他所有内容。无论使用哪种结构,都无法避免这种情况。
对于另一种情况,你可能希望将用户ID置于日期之前,并作为第一个元素放入索引中。那么你的查询就非常简单了:
db.post.find({ "votes.userId": "12ac" })
.sort({ "votes.userId": 1, "votes.date": 1 })
但是你可能会想知道,突然间你失去了一些东西,因为在以前,获取“赞”和“踩”的数量就像测试数组大小一样容易,但现在有些不同了。不过这并不是不能通过使用聚合函数解决的:
db.post.aggregate([
{ "$unwind": "$votes" },
{ "$group": {
"_id": {
"_id": "$_id",
"active": "$active"
},
"likes": { "$sum": { "$cond": [
{ "$eq": [ "$votes.type", "like" ] },
1,
0
]}},
"dislikes": { "$sum": { "$cond": [
{ "$eq": [ "$votes.type", "dislike" ] },
1,
0
]}}
])
所以,无论您实际使用的形式如何,都可以将文档中的任何重要部分存储在组合_id
中,然后轻松地评估“喜欢”和“不喜欢”的数量。
您可能还没有注意到,将一个条目从“喜欢”更改为“不喜欢”也可以通过单个原子更新完成。
您可以做更多的事情,但出于给定原因,我更喜欢这种结构。