0

这个问题与这个问题有关:simple vote system with MongoDB

我有一组可以被用户赞成或反对的项目。我想知道如何检索一些项目,同时知道我是否对它们投了赞成票或反对票。

项目集合包含或多或少类似于这些的项目:

{
  _id:0,
  name:'Item 0',
  upVoters: [ 1, 2 ],
  downVoters: [ 3, 4 ]
}
{
  _id:1,
  name:'Item 1',
  upVoters: [ 1, 3 ],
  downVoters: [ 4 ]
}
{
  _id:2,
  name:'Item 2',
  upVoters: [ ],
  downVoters: [ 2 ]
}

这意味着,例如,项目 0 被 id 为 1 和 2 的用户投票赞成,而用户 3 和 4 投票反对。

如果我是用户 2 并获得了这些项目,我想知道我对项目 0 投了赞成票,对项目 1 投了反对票,对项目 2 投了反对票。

如何执行该查询?如果可能的话,我想只用一个查询来完成。我想我必须使用聚合,但我找不到这样做的方法。

如果我从用户 2 的角度查询项目的预期结果:

{
  _id:0,
  name:'Item 0',
  user_vote: 1
}
{
  _id:1,
  name:'Item 1',
  user_vote: 0
}
{
  _id:2,
  name:'Item 2',
  user_vote: -1
}

如果有帮助,我可以更改集合形状。例如,我可以使用类似于我在上面链接的问题中提出的模型。

替代型号:

{
  _id:0,
  name:'Item 0',
  voters: [
    { id:1, vote:+1}, { id:2, vote:+1},
    { id:3, vote:-1}, { id:4, vote:-1}
  ]
}
{
  _id:1,
  name:'Item 1',
  voters: [
    { id:1, vote:+1}, { id:3, vote:+1},
    { id:4, vote:-1}
  ]
}
{
  _id:2,
  name:'Item 2',
  voters: [
    { id:2, vote:-1}
  ]
}

非常感谢

——费兰

编辑:

正如我在评论中所说,到目前为止,我发现的解决方案是发送 3 个查询:一个获取投票赞成的项目,另一个获取投票反对的项目,另一个获取未投票的项目:

为用户获取项目和投票的临时解决方案

db.items.find({ upVoters:USER_ID })
db.items.find({ downVoters:USER_ID })
db.items.find({ upVoters:{$ne:USER_ID}, downVoters:{$ne:USER_ID} })
4

2 回答 2

4

如果您将第二个示例用作模式,则可以像这样进行聚合:

db.coll2.aggregate([
   // Split items by vote
   {$unwind:"$voters"},
   // Set vote to "0" for votes the user didn't cast
   {$project:{"vote":{$cond:[{$eq:["$voters.id",2]},"$voters.vote",0]}}},
   // Sum the votes for each item for this user (will get rid of 0-vote if user actually voted)
   {$group:{"_id":"$_id", "vote":{$sum:"$vote"}}}])

以达到您正在寻找的结果。需要注意的一点是,如果某个项目没有投票,那么该$unwind步骤将不允许该文档通过管道的其余部分,因此您不会知道给定用户没有投票。尝试对您的第一个提议的模式进行聚合查询也是一个问题,因为直觉上我们必须$unwind同时处理upVoters and downVoters,如果其中一个数组为空,则文档将不会通过管道。

如果您试图访问用户经常投的票,那么可能值得以某种方式存储投票,以便您为他们建立索引user_id和/或item_id(上面的聚合查询不能利用索引)。您可以将投票存储在他们自己的集合中,例如:

{
    item_id:0,
    user_id:1,
    vote:1
}
{
    item_id:0,
    user_id:4,
    vote:-1
}
{
    item_id:2,
    user_id:2,
    vote:-1
}

这允许您在不聚合的情况下提取所需的数据,并且可能是一个更快的选择,也可以使用 和 上的user_id索引 item_id

于 2013-09-19T18:04:51.993 回答
0

就在我的脑海中,您可能必须 $unwind upVoters 和 downVoters 数组,然后进行匹配,类似于:

db.votes.aggregate([
  {$unwind: "$upVoters"},
  {$group: {"_id": "upVoters"}},
  {$match:{"_id.upVoters": {"$in": [2]}}}
])

(我有大约 99% 的把握,你需要稍微修改一下 :))

于 2013-09-12T23:38:09.457 回答