MongoDB-查询以获取项目,并知道我是否对其进行了投票

MongoDB-查询以获取项目,并知道我是否对其进行了投票,mongodb,aggregation-framework,Mongodb,Aggregation Framework,这个问题与这个问题有关: 我有一个项目的集合,用户可以对其投赞成票或反对票。我想知道我如何检索一些项目,同时知道我是否投票赞成或反对 项目集合包含的项目或多或少类似于以下内容: { _id:0, name:'Item 0', upVoters: [ 1, 2 ], downVoters: [ 3, 4 ] } { _id:1, name:'Item 1', upVoters: [ 1, 3 ], downVoters: [ 4 ] } { _id:2, n

这个问题与这个问题有关:

我有一个项目的集合,用户可以对其投赞成票或反对票。我想知道我如何检索一些项目,同时知道我是否投票赞成或反对

项目集合包含的项目或多或少类似于以下内容:

{
  _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 ]
}
{
  _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}
  ]
}
这意味着,例如,项目0由ID为1和2的用户投票赞成,而由ID为3和4的用户投票反对

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

如何执行该查询?如果可能的话,我只想用一个查询就可以了。我想我必须使用聚合,但我找不到方法

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

{
  _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 ]
}
{
  _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}
  ]
}
如果有帮助,我可以更改集合形状。例如,我可以使用一个类似于我在上面链接的问题中提出的模型

备选型号:

{
  _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 ]
}
{
  _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} })

就在我的脑海中,你可能需要解开UpVorters和DownVorters数组,然后进行匹配,大致如下:

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

(我大约99%确定你需要重新做一点:)

仅仅从我的头顶开始,你可能需要$unwind up-vorters和down-vorters数组,然后进行匹配,大致如下:

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

(我大约99%确信您需要对其进行一点修改:)

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

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
下拉列表
,如果其中一个数组为空,则 文件无法通过管道

如果您试图访问用户经常投的票,那么 可能值得以某种方式存储选票,以便您建立 在
user\u id
和/或
item\u 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\u id

item\u id

如果将第二个示例用作模式,则可以执行如下聚合:

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
下拉列表
,如果其中一个数组为空,则 文件无法通过管道

如果您试图访问用户经常投的票,那么 可能值得以某种方式存储选票,以便您建立 在
user\u id
和/或
item\u 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\u id

item\u id

到目前为止,我找到的一个解决方案是查询3次。一个是获得赞成票的项目,另一个是获得反对票的项目,第三个是获得未投票的项目。我在@Tamas的回答中对此进行了评论。如果我能将数组简化为布尔值,那也太好了,就像这里建议的那样:。这样我就可以得到一个布尔值来表示upVote,另一个布尔值表示downVote。我想我既不能像他们那样使用
$cond
,因为似乎
$cond
不能用来检查数组中是否有值。到目前为止,我找到的一个解决方案是查询3次。一个是获得赞成票的项目,另一个是获得反对票的项目,第三个是获得未投票的项目。我在@Tamas的回答中对此进行了评论。如果我能将数组简化为布尔值,那也太好了,就像这里建议的那样:。这样我就可以得到一个布尔值来表示upVote,另一个布尔值表示downVote。我想我不能像他们那样使用
$cond
,因为似乎
$cond
不能用于检查数组中是否有值。谢谢,但我认为该查询得到的是用户向上投票的项。然后,您将不得不发送另一个查询以获取未投票的项目,并发送另一个查询以获取未投票的项目。事实上,您可以在没有聚合的情况下执行此操作:
db.items.find({upvorters:2})
。到目前为止,这是我找到的最好的解决方案,尽管我不太喜欢。谢谢,但我认为这个查询得到了用户投票的项目。然后,您将不得不发送另一个查询以获取未投票的项目,并发送另一个查询以获取未投票的项目。事实上,您可以在没有聚合的情况下执行此操作:
db.items.find({upvorters:2})
。到目前为止,这是我找到的最好的解决方案,尽管我不太喜欢。