2015-06-06 35 views
1

我有一个MongoDB的集合,投票与下面的模式猫鼬聚集如何做嵌套数组文件

{ 
"options" : [ 
       { 
       "_id" : Object Id, 
       "option" : String, 
       "votes" : [ Object Id ] // object ids of users who voted 
       },..... 
      ] 
} 

假设我有节点JS用户的用户id我向他们要发这个信息。我的任务是

(1)在上面的json对象(我​​使用猫鼬)中包含一个额外的字段。

“myVote”:option._id

我需要找到option._id针对

选项[someIndex] .votes包含用户id

(2)更改每个选项中现有的“投票”字段,以表示特定选项的投票数例如,在可见

例子:

{ 
    "options" : [ 
       { 
       "_id" : 1, 
       "option" : "A", 
       "votes" : [ 1,2,3 ] 
       }, 
       { 
       "_id" : 2, 
       "option" : "B", 
       "votes" : [ 5 ] 
       }, 
       { 
       "_id" : 3, 
       "option" : "C", 
       "votes" : [ ] 
       } 
      ] 
} 

所以,如果一个用户ID为我的用户= 5希望看到投票的话,我需要发送以下信息:

预期结果:

{ 
    "my_vote" : 2,   // user with id 5 voted on option with id 2 
    "options" : [ 
       { 
       "_id" : 1, 
       "option" : "A", 
       "votes" : 3    //num of votes on option "A" 
       }, 
       { 
       "_id" : 2, 
       "option" : "B", 
       "votes" : 1    //num of votes on option "B" 
       }, 
       { 
       "_id" : 3, 
       "option" : "C", 
       "votes" : 0   //num of votes on option "C" 
       } 
      ] 
} 
+1

嘿?你想要什么?请尝试添加您尝试过的内容以及预期的结果。 –

+0

这里的例子和结果看起来与发布的原始结构高度不一致。另外,“id = 5”怎么会因此而发挥作用呢?在您选择添加附加信息时,“标记”向您发表评论的人也是习惯和礼貌的要求。帮助人们知道你在做什么。 –

+1

@ user3561036对不起abt之前没有标记,预期的结果实际上是我想发送给客户端的json。我认为这可以通过使用聚合框架来实现,但由于我是新手,无法编写精确查询 –

回答

1

因为它是你居然问,既不真正在当前接受的答案提供,也在于它做了一些不必要的东西,还有另一种方法的问题:

var userId = 5; // A variable to work into the submitted pipeline 

db.sample.aggregate([ 
    { "$unwind": "$options" }, 
    { "$group": { 
     "_id": "$_id", 
     "my_vote": { "$min": { 
      "$cond": [ 
       { "$setIsSubset": [ [userId], "$options.votes" ] }, 
       "$options._id", 
       false 
      ] 
     }}, 
     "options": { "$push": { 
      "_id": "$options._id", 
      "option": "$options.option", 
      "votes": { "$size": "$options.votes" } 
     }} 
    }} 
]) 

这当然会给每个文档输出你这样的:

{ 
    "_id" : ObjectId("5573a0a8b67e246aba2b4b6e"), 
    "my_vote" : 2, 
    "options" : [ 
      { 
        "_id" : 1, 
        "option" : "A", 
        "votes" : 3 
      }, 
      { 
        "_id" : 2, 
        "option" : "B", 
        "votes" : 1 
      }, 
      { 
        "_id" : 3, 
        "option" : "C", 
        "votes" : 0 
      } 
    ] 
} 

所以,你在这里做什么,以先分解为检查阵列使用$unwind。以下$group阶段(以及唯一需要的其他阶段)利用$min$push运营商进行重新构建。

内每个这些操作的,该操作$cond测试经由$setIsSubset阵列内容,要么返回匹配_id值或false。在重建内部数组元素时,请指定$push的参数中的所有元素,而不仅仅是顶级文档,并使用$size运算符来计算数组中的元素。

您还提到了另一个关于与$unwind处理空数组问题的链接。这里的$size运营商将做正确的事情,所以它不需要$unwind,并在这种情况下投射数组为空的“虚拟”值。


大注,除非你实际上是通过它通常会建议在客户端代码,而不是聚合框架做这个操作文件“聚集”。使用$unwind可有效地为每个文档中包含的每个数组元素在聚合管道中创建一个新文档,这会产生大量开销。

对于仅对不同文档执行操作的操作,客户端代码更有效地分别处理每个文档。


如果你真的要坚持该服务器的处理是这样做的方法,那么这可能是最有效的使用$map代替:

db.sample.aggregate([ 
    { "$project": { 
     "my_vote": { 
      "$setDifference": [ 
       { "$map": { 
        "input": "$options", 
        "as": "o", 
        "in": { "$cond": [ 
         { "$setIsSubset": [ [userId], "$$o.votes" ] }, 
         "$$o._id", 
         false 
        ]} 
       }}, 
       [false] 
      ] 
     }, 
     "options": { "$map": { 
      "input": "$options", 
      "as": "o", 
      "in": { 
       "_id": "$$o._id", 
       "option": "$$o.option", 
       "votes": { "$size": "$$o.votes" } 
      } 
     }} 
    }} 
]) 

所以这只是“工程”再加工结果为每个文件。该my_vote是不一样的,虽然,因为它是单一元件阵列(或可能的多个匹配),该聚合框架缺少运营商降低到非数组元素没有进一步的开销:

{ 
    "_id" : ObjectId("5573a0a8b67e246aba2b4b6e"), 
    "options" : [ 
      { 
        "_id" : 1, 
        "option" : "A", 
        "votes" : 3 
      }, 
      { 
        "_id" : 2, 
        "option" : "B", 
        "votes" : 1 
      }, 
      { 
        "_id" : 3, 
        "option" : "C", 
        "votes" : 0 
      } 
    ], 
    "my_vote" : [ 
      2 
    ] 
} 
0

Check out this question

这不是要求同样的事情,但没有办法做你没有多重查询无论如何要求。 我会修改您直接返回的JSON,因为您只是显示查询结果中已包含的额外信息。

  1. 保存您要查询的userID
  2. 取出查询结果(对象中的选项数组),搜索数组中每个元素的votes
  3. 当您找到合适的投票时,请附上_id(如果您没有找到投票,可能会添加'n/a')。

写,做2和3的功能,并且你可以通过它userID,并得到一个新的对象附有myVote

我不认为这样做会比在Mongoose中做另一个查询要慢。