本文介绍了如何在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'的文档,该文档有3条消息,两条消息来自'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毫秒来查询结果,为了进行仿真,我的收藏有3个文档,每个文档都有4个子文档的msg数组.对我来说,28毫秒对于查询来说有点太多了,是的,现在我还在'user'字段上建立了索引.

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函数与和reduce重塑最终结果,或者在发出函数中重命名字段.

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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 03:41