Nodejs 看个Mongodb -〉mapReduce sort的问题。

Nodejs 看个Mongodb -〉mapReduce sort的问题。

异常是这个: exception: could not create cursor over nodejs.loginHistory for query : {} sort : { times: 1 } 上代码:

// map-reduce
			var map = function(){
				emit(this.user.username , {userinfo : this.user, count : 1});
			};
			var reduce = function(key, vals){
				var result = {userinfo : null, count : 0};
				
				if(vals && vals.length > 0){
					result.count = vals.length;
					result.userinfo = vals[vals.length-1].userinfo;
				}
				
				return result;
			};
			var opts = {limit : 10 ,out : {inline:1} }; //sort : {'times': -1} ,
			db.collection('loginHistory').mapReduce(map,reduce, opts, function (err,datas){
//				console.log(err);
//				console.log(util.inspect(datas));
				res.json( {err: err, datas:datas } );
			});
\n```
在var opts = {limit : 10 ,out : {inline:1} };  这里我这个sort是这样的sort : {'times': -1} , 但加上后就报那个错。
有知道的朋友帮忙回复下。

3 回复

Node.js 中 MongoDB 的 mapReduce 和排序问题

背景信息

你遇到了在使用 MongoDB 的 mapReduce 方法时,尝试添加排序(sort)功能导致的错误。具体来说,你在 opts 对象中添加了 sort 属性,结果引发了错误。

错误原因

在 MongoDB 的 mapReduce 方法中,sort 属性并不被直接支持。mapReduce 是一个复杂的操作,它包括映射(map)、归约(reduce)以及输出(output),但它并没有内置对查询结果排序的支持。

解决方案

要在 mapReduce 结果中实现排序,可以考虑以下两种方法:

  1. 在客户端排序:在 mapReduce 操作完成后,在客户端进行排序。
  2. 使用聚合管道(Aggregation Pipeline):聚合管道提供了更灵活的操作,包括排序、过滤等功能。

这里提供第二种方法的示例代码:

// 使用聚合管道代替 mapReduce
db.collection('loginHistory').aggregate([
    {
        $group: {
            _id: "$user.username",
            userinfo: { $last: "$user" },
            count: { $sum: 1 }
        }
    },
    {
        $sort: { "count": -1 } // 按 count 倒序排序
    },
    {
        $limit: 10 // 只取前 10 条记录
    }
], function (err, result) {
    if (err) {
        console.error("Error executing aggregate pipeline:", err);
        res.json({ err: err });
    } else {
        res.json({ datas: result });
    }
});

示例代码解释

  1. $group: 将文档按用户名分组,并计算每个用户的登录次数 (count)。同时保留每个用户最后一条登录记录的用户信息 (userinfo)。
  2. $sort: 按照 count 字段倒序排序结果。
  3. $limit: 限制返回的结果数量为前 10 条。

这种方法不仅避免了 mapReduce 的复杂性,还利用了 MongoDB 聚合管道的强大功能来实现排序和限制结果数量的功能。


sort 里的索引必须是在集合上已定义过的索引,如果尚未定义 sort key 匹配的索引将会报错。

在MongoDB的mapReduce中,直接添加sort选项会导致错误。mapReduce并不支持直接在opts对象中指定排序参数。你需要先运行find查询来获取排序后的数据,然后再应用mapReduce

以下是如何修改你的代码以实现排序:

db.collection('loginHistory')
  .find({}) // 你可以根据需要调整查询条件
  .sort({ times: -1 }) // 按 'times' 字段降序排序
  .limit(10) // 限制结果数量
  .mapReduce(
    function() {
      emit(this.user.username, { userinfo: this.user, count: 1 });
    },
    function(key, vals) {
      var result = { userinfo: null, count: 0 };
      if (vals && vals.length > 0) {
        result.count = vals.length;
        result.userinfo = vals[vals.length - 1].userinfo;
      }
      return result;
    },
    { out: { inline: 1 } }, // 或者可以设置为一个集合名 { out: "outputCollection" }
    function(err, res) {
      if (err) {
        console.error("Error:", err);
      } else {
        res.json({ err: err, datas: res });
      }
    }
  );

这段代码首先对查询结果进行排序和限制,然后将排序后的数据传递给mapReduce函数。这样可以避免因直接在opts中添加sort选项而导致的错误。

回到顶部