如何使用$ unwind解决空数组?

时间:2016-04-19 17:33:18

标签: mongodb mongodb-query aggregation-framework

我有一张桌子并保存如下:

{ "_id" : ObjectId("5716617f4af77ca97a9614bd"), "count" : 1, "author" : "Tony", "music" : [ { "_id" : ObjectId("571661cd4af77ca97a9614c1"), "count" : 2, "author" : "Tony" } ] }
{ "_id" : ObjectId("5716617f4af77ca97a9614be"), "count" : 2, "author" : "Joe", "music" : [ { "_id" : ObjectId("571661cd4af77ca97a9614c0"), "count" : 1, "author" : "Joe" } ] }
{ "_id" : ObjectId("5716617f4af77ca97a9614bf"), "count" : 3, "author" : "Mary", "music" : [ ] }

我希望找到“$ count”>的记录数量。 “$ music.count”。但当我做{$ unwind:“$ music”}时,我得到了以下信息:

{ "_id" : ObjectId("5716617f4af77ca97a9614bd"), "count" : 1, "author" : "Tony", "music" : { "_id" : ObjectId("571661cd4af77ca97a9614c1"), "count" : 2, "author" : "Tony" } }
{ "_id" : ObjectId("5716617f4af77ca97a9614be"), "count" : 2, "author" : "Joe", "music" : { "_id" : ObjectId("571661cd4af77ca97a9614c0"), "count" : 1, "author" : "Joe" } }

第三条记录消失了。我怎样才能得到如下结果:

{ "_id" : ObjectId("5716617f4af77ca97a9614bd"), "count" : 1, "author" : "Tony", "music" : { "_id" : ObjectId("571661cd4af77ca97a9614c1"), "count" : 2, "author" : "Tony" } }
{ "_id" : ObjectId("5716617f4af77ca97a9614be"), "count" : 2, "author" : "Joe", "music" : { "_id" : ObjectId("571661cd4af77ca97a9614c0"), "count" : 1, "author" : "Joe" } }
{ "_id" : ObjectId("5716617f4af77ca97a9614bf"), "count" : 3, "author" : "Mary", "music" : {"count": 0} }

初始记录是通过$ loopup得到的,总代码如下:

db.bookAuthors.aggregate([{
$lookup:{from:"musicAuthors", localField:"author", foreignField:"author",as:"music"}},
{$unwind:"$music"},
{$project:{_id:"$author",count:1,music:1}},
{$match:{$gt:["$count","$music.count"]}},
{$group:{_id:null,count:{$sum:1}}}
])

如何查找“$ count”>的记录数量? “$ music.count”?在这个例子中,结果应该是2.但是现在由于解开问题,我得到1.谢谢。

1 个答案:

答案 0 :(得分:19)

在MongoDB 3.2中(如果您有preserveNullAndEmptyArrays,则使用),$unwind运算符具有db.bookAuthors.aggregate([ { "$lookup":{ "from": "musicAuthors", "localField": "author", "foreignField": "author", "as": "music" }}, { "$unwind": { "path": "$music", "preserveNullAndEmptyArrays": true }, { "$project": { "count": 1, "author": 1, "music": { "$ifNull": [ "$music", { "$literal": { "count": 0 } }] }, } }} ]) 选项。这会将行为更改为“不”从数组实际上为“空”的结果中删除文档:

1:1

在这种情况下,$ifNull会替换缺失值。

但实际上,由于您的关联位于db.bookAuthors.aggregate([ { "$lookup":{ "from": "musicAuthors", "localField": "author", "foreignField": "author", "as": "music" }}, { "$project": { "count": 1, "author": 1, "music": { "$ifNull": [ { "$arrayElemAt": [ "$music", 0 ] }, { "$literal": { "count": 0 } } ] } }} ]) ,因此您可以完全放弃$unwind,只需替换空数组:

0

如果$arrayElemAtdb.bookAuthors.aggregate([ { "$lookup":{ "from": "musicAuthors", "localField": "author", "foreignField": "author", "as": "music" }}, { "$group": { "_id": null, "count": { "$sum": { "$cond": { "if": { "$gt": [ "$count", { "$sum": { "$map": { "input": "$music", "as": "el", "in": "$$el.count" } }} ] }, "then": 1, "else": 0 } } } }} ]) 索引处找不到任何内容(因此为“空”),那么$ifNull将像以前一样返回备用值。当然它确实找到了什么,然后返回该值。

但同样,您的具体问题仍有更好的解决方案,同样不需要$unwind。因为您可以使用数组“in-line”计算“计数”条件:

$sum

这里$sum运算符用在它的两个用例中,因为它是传统的“累加器”,并且是数组中“求和”值的新角色。 $map运算符查看每个数组元素并将值返回0以生成总计。 “空”数组将返回"count"

然后进行$cond比较,以确定数组中返回的总数是否小于文档上的true属性。 1为累加器返回false的位置,以及0获取2的位置。

最终结果当然是public function update(CreateJournalRequest $request, $course_id){ $input = $request->all(); foreach ($input['id'] as $i => $log_id){ $data = [ 'user_id' => \Auth::user()->id, 'course_id' => $course_id, 'weeks' => $i + 1, 'work_description' => $input['work_description'][$i], 'instructor_comments' => $input['instructor_comments'][$i], 'status' => $input['status'][$i], 'created_at' => Carbon::now(), 'updated_at' => Carbon::now(), ]; Journal::where('id', $log_id)->update($data); } return redirect('/student/home'); } ,因为“第一”和“第三”文档实际上与累加器内的条件匹配。所以这确实是最有效的方法,即使它在这个过程中看起来有点“长篇大论”。