Mongodb分组数据-mapReduce还是聚合?

Mongodb分组数据-mapReduce还是聚合?,mongodb,mapreduce,mongodb-query,aggregation-framework,Mongodb,Mapreduce,Mongodb Query,Aggregation Framework,我有这样的文件: { "_id" : ObjectId("565e906bc2209d91c4357b59"), "userEmail" : "abc@example.com", "subscription" : { "project1" : { "subscribed" : false }, "project2" : { "subscribed" : true

我有这样的文件:

{
    "_id" : ObjectId("565e906bc2209d91c4357b59"),
    "userEmail" : "abc@example.com",
    "subscription" : {
        "project1" : {
            "subscribed" : false
        },
        "project2" : {
            "subscribed" : true
        }
    }
}

{
    "_id" : ObjectId("565e906bc2209d91c4357b59"),
    "userEmail" : "mno@example.com",
    "subscription" : {
        "project1" : {
            "subscribed" : true
        },
        "project2" : {
            "subscribed" : true
        },
        "project3" : {
            "subscribed" : true
        }
    }
}
我想按用户对
subscribed
标志设置为
true
的项目列表进行分组

例如,我期望的是:

abc@example.com - project2
mno@example.com - project1,project2,project3
我将有一个cron作业,它将订阅项目的各个详细信息发送到相应的邮件id

我尝试了聚合,但聚合需要指定的密钥。在我的例子中,键(Project1、Project2等等)是动态的。所以我在某处读到
mapReduce
是正确的选择。但是我没有使用
mapReduce
的经验


请帮助我解决此问题,并让我了解如何处理此问题。

对于您需要使用的文档的当前结构

db.subscription.mapReduce(
函数(){
var项目=[];
对于(此.subscription中的键){
if(Object.prototype.hasOwnProperty.call(this.subscription,key)&&this.subscription[key]['subscripted']
{project.push(键);}
} 
发出(this.userEmail,project);
}, 
函数(键,值){},
{out:{'inline':1}
)
返回:

{
“结果”:[
{
“_id”:”abc@example.com",
“价值”:[
“项目2”
]
},
{
“_id”:”mno@example.com",
“价值”:[
“项目1”,
“项目2”,
“项目3”
]
}
],
“timeMillis”:28,
“计数”:{
“投入”:2,
“发射”:2,
“减少”:0,
“产出”:2
},
“好”:1
}

<>你应该考虑改变你的文档结构。为此,您需要更新您的文档,并使用操作更改子文档的“订阅”和数组,以获得最大效率

var bulk=db.subscription.initializeOrderedBulkOp();
var计数=0;
db.subscription.find().forEach(函数(doc){
var newSubscriptions=[];
var subscription=doc.subscription;
对于(注册表项订阅){
if(Object.prototype.hasOwnProperty.call(subscription,key))
push({'project':key,'subscribed':subscription[key]['subscribed']});
}
bulk.find({'u-id':doc.\u-id}).updateOne({
“$set”:{订阅:新闻订阅}
});
计数++;
如果(计数%500==0){
bulk.execute();
db.subscription.initializeOrderedBulkOp();
}
})
//清理队列
如果(计数>0)
bulk.execute();
执行此操作后,您的文档如下所示:

{
    "_id" : ObjectId("565e906bc2209d91c4357b59"),
    "userEmail" : "abc@example.com",
    "subscription" : {
        "project1" : {
            "subscribed" : false
        },
        "project2" : {
            "subscribed" : true
        }
    }
}

{
    "_id" : ObjectId("565e906bc2209d91c4357b59"),
    "userEmail" : "mno@example.com",
    "subscription" : {
        "project1" : {
            "subscribed" : true
        },
        "project2" : {
            "subscribed" : true
        },
        "project3" : {
            "subscribed" : true
        }
    }
}
{
“_id”:ObjectId(“566041212729b51edb5871d4”),
“用户电子邮件”:abc@example.com",
“认购”:[
{
“项目”:“项目1”,
“订阅”:错误
},
{
“项目”:“项目2”,
“订阅”:真
}
]
}
{
“_id”:ObjectId(“565e906bc2209d91c4357b59”),
“用户电子邮件”:mno@example.com",
“认购”:[
{
“项目”:“项目1”,
“订阅”:真
},
{
“项目”:“项目2”,
“订阅”:真
},
{
“项目”:“项目3”,
“订阅”:真
}
]
}
您可以使用
.aggregate()
方法访问聚合管道:

db.subscription.aggregate([
{$project':{
“用户电子邮件”:1,
“项目”:{
“$setDifference”:[
{$map':{
“输入”:“$subscription”,
“as”:“srpt”,
'in':{'$cond':['$$srpt.subscribed','$$srpt.project',false]}
}}, 
[错误]
]
}
}}
])
这将产生:

{
“_id”:ObjectId(“566041212729b51edb5871d4”),
“用户电子邮件”:abc@example.com",
“项目”:[
“项目2”
]
}
{
“_id”:ObjectId(“565e906bc2209d91c4357b59”),
“用户电子邮件”:mno@example.com",
“项目”:[
“项目1”,
“项目2”,
“项目3”
]
}
可能有助于删除带有
subscribed:false
的数组项。如果将订阅更改为数组[{project:“project1”,subscribed:true},…],则可以使用聚合框架轻松完成。否则,您必须使用map reduce或一些客户端代码。