Mongoose:嵌套数组结构中的聚合查询

我遇到了一个MongoDB查询的问题。

我有一个名为“Answers”的集合,具有以下结构

{ "_id": ObjectId("560acfcb904a29446a6d2617"), "path_id": ObjectId("560acae1904a29446a6d2610"), "step_id": "kids", "user_id": ObjectId("559ae27684ff12e88d194eb7"), "answers": [ { "id": "kids_q", "question": "Do you have kids?", "answer": "No" } ] } 

正如你所看到的answers是一个数组,它可以有一个或多个对象,但总是一个数组。

首先,我想在step_id中得到答案的总数

我得到了使用聚合使用下面的查询

 Answer.aggregate( { $match: { 'path_id': { $eq: path_id }, 'step_id': { $eq: step_id }, '' } }, { $group: { _id: { step_id: '$step_id' }, count: { $sum: 1 } } }, function( err, results ) { if ( err ) { deferred.reject( err ); } deferred.resolve( results ); } ); 

这很好。

其次,我想知道有多less答案与这个问题和答案相匹配。

让我们用Do you have kids? 问题为例,我想知道有多less答案Yes ,在命令行中运行查询我得到正确的结果:

 db.answers.find( { path_id: ObjectId( '560acae1904a29446a6d2610' ), 'answers.0.question': 'Do you have kids?', 'answers.0.answer': 'Yes' } ) 

我想把这个查询翻译成一个聚合查询使用mongoose和避免硬编码数组answers.0.question因为答案可以存储在一个随机的索引,也许在索引1,也许在索引7。

任何帮助表示赞赏。

谢谢

真的不知道如果.aggregate()真的是你想要的任何这一点。 如果我理解正确,那么你的集合中有这些文档有一系列的问题答案,当然这些答案不在数组中的任何设置位置。 但是,似乎任何一个文档都不可能有多个相同的答案types。

所以在我看来,所有你真正想要的是数组元素值$elemMatch ,并确定包含它的文档的计数:

 Answer.count({ "path_id": "560acae1904a29446a6d2610", "answers": { "$elemMatch": { "question": "Do you have kids?", "answer": "Yes" } } },function(err,count) { }); 

$elemMatch运算符将所有条件应用到数组的每个元素上,就像另一个查询一样。 因此,在同一个元素上需要满足“和”的多个条件才是有效的。 没有必要通过索引来做到这一点。

如果你想要更广泛的东西,那么只有在每个文档可能包含多个可能的匹配条件的情况下,才会使用.aggregate()和条件来筛选和计算arrays。

 Answer.aggregate( [ { "$match": { "answers": { "$elemMatch": { "question": "Do you have kids?", "answer": "Yes" } } }}, { "$unwind": "$answers" }, { "$match": { "answers.question": "Do you have kids?", "answers.answer": "Yes" }}, { "$group": { "_id": "$path_id", "count": { "$sum": 1 } }} ], function(err,results) { } ); 

但是,我只会做这样的事情,如果你有数组中的多个可能的匹配,你需要在结果内多个键组合。

因此,如果只是在一个数组条目中匹配碰巧具有这些细节的文档,那么只需使用$elemMatch进行查询,而最多只需$group$elemMatch给定键的计数,而不必费心过滤数组内容通过$unwind

 Answer.aggregate( [ { "$match": { "answers": { "$elemMatch": { "question": "Do you have kids?", "answer": "Yes" } } }}, { "$group": { "_id": "$path_id", "count": { "$sum": 1 } }} ], function(err,results) { } ); 

所以如果数组中只有一个可能的匹配,那么只需要对文档进行计数

使用$ unwind ,然后使用$ match来只筛选您正在寻找的问题的答案:

 var steps = [ { $match: { 'path_id': ObjectId("560acae1904a29446a6d2610"), 'step_id': 'kids' } }, { $unwind : "$answers" }, { $match: { "answers.question": 'Do you have kids?' } }, { $group: { _id: '$answers.answer', count: { $sum: 1 } } } ]; Answer.aggregate(steps, function( err, results ) { //do whatever you want with the results } );