如何在Mongoose/MongoDB查询子文档中使用MapReduce?

6
我在mongoose/mongodb中实现了一个简单的消息系统,其模式如下:
var schema = new mongoose.Schema({
    user: {type:String, required:true},
    updated: {type:Date, default:new Date()},       
    msgs: [ {m:String, // message itself 
             d:Date,   // date of message
             s: String,  // message sender
             r:Boolean   // read or not
            } ],
});

所有的消息都存储在msg嵌套数组中,现在我想从特定的发送者查询消息,例如:

{
  "_id" : ObjectId("52c7cbe6d72ecb07f9bbc148"),
  'user':'abc'
  "msgs" : [{
      "m" : "I want to meet you",
      "d" : new Date("4/1/2014 08:52:54"),
      "s" : "user1",
      "r" : false,
      "_id" : ObjectId("52c7cbe69d09f89025000005")
    }, {
      "m" : "I want to meet you",
      "d" : new Date("4/1/2014 08:52:56"),
      "s" : "user1",
      "r" : false,
      "_id" : ObjectId("52c7cbe89d09f89025000006")
    }, {
      "m" : "I want to meet you",
      "d" : new Date("4/1/2014 08:52:58"),
      "s" : "user2",
      "r" : false,
      "_id" : ObjectId("52c7cbea9d09f89025000007")
    }
   }

这里有一个文件,属于用户“aa”,他有三条消息,其中两条消息来自“user1”,一条消息来自“user2”。我想查询来自“user1”的消息。

基本上有两种方法可以做到这一点,分别是map-reduce和aggregate。我尝试了map-reduce的解决方案。

var o = {}; 
o.map = function() { 
    this.msgs.forEach(function(msg){ 
        if(msg.s == person){  emit( msg.s, {m:msg.m,d:msg.d,r:msg.r}); }
    })
}       
o.reduce = function(key, values) {
    var msgs = [];
    for(var i=0;i<values.length;i++)
    msgs.push(values[i]);       
    return JSON.stringify(msgs);
}
o.query  = {user:'username'};  
o.scope = {person:'user1'};
model.mapReduce(o,function (err, data, stats) { 
    console.log('map reduce took %d ms', stats.processtime)
    if(err) callback(err);
    else callback(null,data);
})

最终,它的工作原理就像这样:

 [ 
    { _id: 'helxsz',
    value: '[
        {"m":"I want to meet you","d":"2014-01-04T08:52:54.112Z","r":false}, ....
        ]
 ]

结果是我想要的,但格式有点复杂。如何更改以使输出格式像这样?
    { sender: 'helxsz',
      messages: '[
        {"m":"I want to meet you","d":"2014-01-04T08:52:54.112Z","r":false}, ...
        ]
    }

我需要手动使用reduce函数来对结果进行排序和限制吗?

最后,map reduce方法查询结果需要28毫秒,在模拟中,我的集合有三个文档,每个文档都有一个包含4个子文档的msg数组。对我来说,28毫秒对于查询来说有点太长了,我现在也在'user'字段上建立了索引。

3个回答

0

我不确定这对你来说有多有效率,但是对于格式化而言,下面的代码可以使用自定义键名titleclassNamestart(它们不在集合中)。 因此,将mapReduce的结果存储在一个新的集合中并检索它。(如果您不打算在每个请求上运行mapReduce)

  db.events.aggregate([{
       $project: {
        title: "$value",
        className: "$_id.method",
        start: "$_id.time",
        _id:0 }
   }]
)

0

如果您使用Map-Reduce框架,我不建议使用它,因为它的性能较差,但是您可以使用finalize函数与mapreduce一起来重新塑造最终结果,或者在emit函数中重命名字段。

相反,我建议使用聚合框架,它具有更好的性能:

db.collection.aggregate([
    {$match: {"user" : "user1"}},
    {$project: {"_id": 0, "sender": "$user", "messages": "$msgs"}}
])

-2

在你说的地方,

emit(msg.s, {m:msg.m,d:msg.d,r:msg.r});

改为:

 emit( sender: msg.s, messages: {m:msg.m,d:msg.d,r:msg.r});

иҝҷйҮҢдҪҝз”Ёзҡ„emitж–№жі•жҳҜеңЁMongoDBдёӯдёәmapReduceж“ҚдҪңе®ҡд№үзҡ„гҖӮ - gnerkus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接