tes*_*ode 6 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" : [ ] }
Run Code Online (Sandbox Code Playgroud)
我希望找到"$ 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" } }
Run Code Online (Sandbox Code Playgroud)
第三条记录消失了.我怎样才能得到如下结果:
{ "_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} }
Run Code Online (Sandbox Code Playgroud)
初始记录是通过$ 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}}}
])
Run Code Online (Sandbox Code Playgroud)
如何查找"$ count">"$ music.count"的记录数?在这个例子中,结果应该是2.但是现在由于解开问题,我得到1.谢谢.
Nei*_*unn 19
在MongoDB 3.2中(如果有的话,您可以使用$lookup),$unwind操作员可以preserveNullAndEmptyArrays选择.这会将行为更改为"不"从数组实际上为"空"的结果中删除文档:
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 } }] },
}
}}
])
Run Code Online (Sandbox Code Playgroud)
并且$ifNull在这种情况下替换了缺失值.
但实际上,既然你在这里的关联是完全1:1放弃$unwind了,只需要替换空数组:
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 } }
]
}
}}
])
Run Code Online (Sandbox Code Playgroud)
如果$arrayElemAt在0索引处找不到任何内容(因此为"空"),那么$ifNull将像以前一样返回备用值.当然它确实找到了什么,然后返回该值.
但同样,您的具体问题仍然有一个更好的解决方案,这也是不需要的$unwind.因为您可以使用数组"内联"计算"计数"条件:
db.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
}
}
}
}}
])
Run Code Online (Sandbox Code Playgroud)
这里的$sum运算符用于它的两个用例,因为它是传统的"累加器"和数组中"求和"值的新角色.的$map操作者查看每个阵列元素,并返回值,以$sum产生总计."空"数组将返回为0.
然后$cond进行比较以确定数组中返回的总数是否小于"count"文档中的属性.其中truea 1为累加器返回,以及false它到达的位置0.
最终结果当然是2因为"第一"和"第三"文件实际上与累加器内的条件匹配.所以这确实是最有效的方法,即使它在这个过程中看起来有点"长篇大论".