如何在 mongoose/mongodb 查询子文档中使用 mapreduce? [英] how to use mapreduce in mongoose/mongodb query subdocument?

查看:31
本文介绍了如何在 mongoose/mongodb 查询子文档中使用 mapreduce?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在mongoose/mongodb中实现了一个简单的消息系统,架构如下

I implemented a simple message system in mongoose/mongodb, the schema is like the following

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 嵌套数组中,现在我想查询来自某个发件人的消息,例如,

all the messages are stored in msg nested array, now I want to query the messages from certain sender, for example,

{
  "_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'的消息

Here I have a document for user 'aa' who has three messages, two messages are from 'user1' and one message is from 'user2'. And I want to query for the messages from 'user1'

基本上有两种方法可以做到这一点,map-reduce 或聚合.我尝试了 map-reduce 解决方案.

Basically there are two ways to do it, map-reduce or aggregate. I tried the map-reduce solution.

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);
})

最终,它适用于类似的结果

Ultimately, it works with results like

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

结果是我想要的,但是格式有点复杂.如何更改以使输出格式像这样

The result is what I want, but the format is a bit complex. How can I change to make output the format like this

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

以及我如何对结果进行排序和限制,所以我必须手动执行reduce函数?

and how I sort and limit the results, so I have to manually do it the reduce function?

最后一个 map reduce 方法需要 28 毫秒来查询结果,为了模拟,我的集合有三个文档,每个文档都有一个包含 4 个子文档的 msg 数组.对我来说,28 毫秒对于查询来说有点太多了,是吗,现在我还索引了用户"字段.

and one last the map reduce methods takes 28 ms to query the result, for the simulation, my collection has three documents, each document has a msg array of 4 subdocument. for me , 28 ms is a bit of too much for the query, is it , now I also indexed on the 'user' field.

推荐答案

如果你使用map-reduce框架,由于性能我不推荐,那么你可以使用finalize函数与 mapreduce 一起重塑最终结果,或者在发出函数期间重命名字段.

If you use the map-reduce framework, which I do not recommend due to its performance, then you can use the finalize function together with the map and reduce to reshape the final result or alternatively, rename the fields during in the emit functions.

我建议使用性能更好的聚合框架:

Instead I recommend using the aggregation framework which has much better performance:

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

这篇关于如何在 mongoose/mongodb 查询子文档中使用 mapreduce?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆