Mongoose计算模式数组

时间:2016-10-16 20:53:06

标签: node.js mongodb mongoose

我需要在模式中查找元素并计算它们发送的总消息数。 我已经尝试过上面这段代码,但对我不起作用。

User.find({type: 'psycologist'}).exec(function (err, users) {
    if(err){
        callback(new Error("Something went wrong"), null);
    }else{

        Message.count({userFrom: { "$in" : users} }).exec(function (err, counter) {
            if(err){
                callback(new Error("Something went wrong."), null);
            }else{
                console.log(counter); //displays 0
                callback(null, counter);
            }
        });
    }
});

消息架构

var schema = new Schema({
    content: {type: String, required: true},
    type: {type: String, required: true, default: 'text'},
    status: {type: String, default: 'not_read'},
    created_at: {type: Date, default: Date.now},
    userFrom: {type: Schema.Types.ObjectId, ref: 'User', required: true},
    userTo: {type: Schema.Types.ObjectId, ref: 'User', required: true}
});

用户架构

var schema = new Schema({
    name: {type: String, required: true},
    email: {type: String, required: true, unique: true},
    phone: {type: String, required: true},
    password: {type: String, required: true, select: false},
    type: {type: String, required: true},
    created_at: {type: Date, required: true, default: Date.now}
});

有人知道如何修复它或更好的方法吗? 提前谢谢。

如果这里有任何专家mongo可以告诉我有关此查询对大量数据的性能的详细信息。

3 个答案:

答案 0 :(得分:1)

问题是你第一次找到的结果是一组用户,它是完整的文件。 您只能为$in查找运算符使用一组值。

将其更改为:

User.find({type: 'psycologist'}).exec(function (err, users) {
    if(err){
        callback(new Error("Something went wrong"), null);
    }else{
        var MyUserIdArray = users.map(function(x) { return x._id} );
        Message.count({userFrom: { "$in" : MyUserIdArray} }).exec(function (err, counter) {
            if(err){
                callback(new Error("Something went wrong."), null);
            }else{
                console.log(counter); //displays 0
                callback(null, counter);
            }
        });
    }
});

答案 1 :(得分:1)

更好的方法是使用聚合框架运行管道,该管道使用 $lookup 运算符在messages集合上执行“左连接” users集合。

考虑运行以下聚合管道:

Users.aggregate([
    { "$match": { "type": "psycologist"} },
    {
        "$lookup": {
            "from": "messages",
            "localField": "_id",
            "foreignField": "userFrom",
            "as": "messagesFrom"
        }
    },  
    { 
        "$project": {
            "messages": { "$size": "$messagesFrom" }            
        }
    },
    {
        "$group": {
            "_id": null,
            "counter": { "$sum": "$messages" }
        }
    }
]).exec(function(err, result) {
    if(err){
        callback(new Error("Something went wrong."), null);
    }else{
        console.log(JSON.stringify(result, null, 4)); 
        callback(null, result[0].counter);
    }
});

在上面的聚合操作中,第一步是 $match 运算符,它过滤文档流以仅允许匹配的文档未经修改地传递到下一个管道阶段,并且可以将其作为其参数MongoDB查询语法。这类似于MongoDB Collection的find()方法和SQL的WHERE子句,过滤器{ "$match": { "type": "psycologist"} }

相同
User.find({type: 'psycologist'})

在下一个管道中,过滤后的文档会传递给 $lookup 运算符,该运算符对同一数据库中的messages集合执行左外连接以过滤来自“加入”集合的文件进行处理。 “as”选项是要添加到输入文档的新数组字段的名称。新数组字段包含“from”集合中的匹配文档。

然后,您需要获取此数组的长度,因为它表示每个用户的消息数。这可以在下一个管道中使用 $project 运算符实现,该运算符重新整形流中的每个文档,包含,排除或重命名字段,注入计算字段,创建子文档字段,使用数学表达式,日期,字符串和/或逻辑(比较,布尔,控制)表达式。

在这种情况下,您使用 $size 运算符,该运算符返回数组中的元素数,从而获得每个用户的邮件数。

最后的管道步骤是 $group ,它汇总了所有文档。它按指定的标识符表达式对输入文档进行分组,并应用累加器表达式。但在这种情况下,您指定_idnull来计算所有输入文档的累计值。您使用在messages字段上应用的 $sum 累加器运算符(从前一个管道计算)聚合所有消息计数,从而获得特定消息的总数用户类型。

答案 2 :(得分:0)

尝试

User.find({type: 'psycologist'}, {_id: 1}).exec(function (err, users) {
    if(err){
        callback(new Error("Something went wrong"), null);
    }else{
        var ids = users.map(function(user){
           return user._id;
        })
        Message.count({userFrom: { "$in" : ids } }).exec(function (err, counter) {
            if(err){
                callback(new Error("Something went wrong."), null);
            }else{
                console.log(counter); //displays 0
                callback(null, counter);
            }
        });
    }
});