Nodejs中mongoskin处理bind后的函数时似乎有问题

Nodejs中mongoskin处理bind后的函数时似乎有问题

db.bind(‘tag’, {
inc: function(name) {
console.log(‘function inc’);
this.update({name: name}, {’$inc’: {count: 1}}, {upsert: true}, function() {
console.log(‘inc callback’);
});
},

dec: function(name) {
    console.log('function dec');
    var self = this;
    self.update({name: name}, {'$inc': {count: -1}}, {upsert: true}, function() {
        console.log('function dec callback');
        self.findOne({name: name}, function(error, item){
            if (item && item.count <= 0) {
                self.remove(item);
            }
        })
    });
},

all: function(callback) {
    console.log('function all');
    this.find().toArray(callback);
}

});

for (var i = 0; i < 1000; i++) { db.tag.inc(‘电影’); }

for (var i = 0; i < 500; i++) { db.tag.dec(‘电影’); }

db.tag.all(function(err, data) { console.log(‘function all callback’); for (var index in data) { console.dir(data); } })

多运行几次,看输出。会发现所有的操作是串行的。不知道是因为mongo native的驱动本身就是串行的还是因为mongoskin在处理的时候串行的。

为了测试是不是因为mongo native驱动的问题,然后用mongoose写了一个另外类似功能的代码,如下:

var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

var TagSchema = new Schema({ name : { type: String, index: true }, count : { type: Number }, });

TagSchema.statics.inc = function(name) { console.log(‘function inc’); this.update({name: name}, {’$inc’: {count: 1}}, {upsert: true}, function() { console.log(‘function inc callback!’); }); }

TagSchema.statics.dec = function(name) { console.log(‘function dec’); var self = this; self.update({name: name}, {’$inc’: {count: -1}}, {upsert: true}, function(error) { console.log(‘function dec callback’); if (error) { return; }

    self.findOne({name: name}, function(error, item) {
        if (error) {
            return;
        }
        
        if (item &amp;&amp; item.count &lt;= 0) {
            item.remove();
        } 
    });
});

}

TagSchema.statics.all = function(callback) { console.log(‘function all’); this.find().desc(‘count’).exec(callback); }

var Tag = mongoose.model(‘Tag’, TagSchema); mongoose.connect(‘mongodb://localhost/testdb2’);

for (var i = 0; i < 1000; i++) { Tag.inc(‘电影’); }

for (var i = 0; i < 500; i++) { Tag.dec(‘电影’); }

Tag.all(function(err, data) { console.log(‘function all callback’); for (var index in data) { console.dir(data); } })

任然是运行看结果。你会发现,mongoose不是串行的。


9 回复

Node.js 中 Mongoskin 处理 bind 后的函数时似乎存在问题

问题描述

在使用 mongoskin 绑定集合并定义自定义方法时,发现这些方法在并发执行时表现得像是串行的。这可能是因为 mongoskin 在处理这些绑定方法时存在某些限制或问题。

示例代码

// 使用 mongoskin 进行操作
var mongo = require('mongoskin');
var db = mongo.db("localhost:27017/test", {native_parser:true});

db.bind('tag', {
    inc: function(name) {
        console.log('function inc');
        this.update({name: name}, {'$inc': {count: 1}}, {upsert: true}, function() {
            console.log('inc callback');
        });
    },
    
    dec: function(name) {
        console.log('function dec');
        var self = this;
        self.update({name: name}, {'$inc': {count: -1}}, {upsert: true}, function() {
            console.log('dec callback');
            self.findOne({name: name}, function(error, item){
                if (item && item.count <= 0) {
                    self.remove(item);
                }
            })
        });
    },
    
    all: function(callback) {
        console.log('function all');
        this.find().toArray(callback);
    }
});

for (var i = 0; i < 1000; i++) {
    db.tag.inc('电影');
}

for (var i = 0; i < 500; i++) {
    db.tag.dec('电影');
}

db.tag.all(function(err, data) {
    console.log('all callback');
    for (var index in data) {
        console.dir(data);
    }
});

观察结果

多次运行上述代码,可以看到所有的 incdec 操作似乎是串行执行的,而不是并发的。这意味着 mongoskin 可能在处理这些操作时存在某种同步机制。

对比 Mongoose

为了验证问题是否出在 mongoskin 上,我们使用 mongoose 重写了相同的功能:

var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

mongoose.connect('mongodb://localhost/testdb2');

var TagSchema = new Schema({
    name  : { type: String, index: true },
    count : { type: Number },
});

TagSchema.statics.inc = function(name) {
    console.log('function inc');
    this.update({name: name}, {'$inc': {count: 1}}, {upsert: true}, function() {
        console.log('inc callback');
    });
};

TagSchema.statics.dec = function(name) {
    console.log('function dec');
    var self = this;
    self.update({name: name}, {'$inc': {count: -1}}, {upsert: true}, function(error) {
        console.log('dec callback');
        if (error) {
            return;
        }

        self.findOne({name: name}, function(error, item) {
            if (error) {
                return;
            }

            if (item && item.count <= 0) {
                item.remove();
            } 
        });
    });
};

TagSchema.statics.all = function(callback) {
    console.log('function all');
    this.find().sort({count: -1}).exec(callback);
};

var Tag = mongoose.model('Tag', TagSchema);

for (var i = 0; i < 1000; i++) {
    Tag.inc('电影');
}

for (var i = 0; i < 500; i++) {
    Tag.dec('电影');
}

Tag.all(function(err, data) {
    console.log('all callback');
    for (var index in data) {
        console.dir(data);
    }
});

观察结果

使用 mongoose 时,incdec 操作是并发执行的,而不是串行的。这表明问题确实出在 mongoskin 的处理方式上。

结论

mongoskin 在处理绑定方法时可能存在某种同步机制,导致并发操作表现得像是串行的。如果需要并发处理,建议考虑使用其他库如 mongoose


大侠,请问您如何得知console有dir这个方法的?

mongoose 不能用用户名加密码的形式连接么

贴一下输出吧,不理解你的意思

代码解释:

先看第一个for循环:

for (var i = 0; i < 1000; i++) {
    db.tag.inc('电影');
}

这里db.tag.inc会直接调用函数

inc: function(name) {
        console.log('function inc');
        this.update({name: name}, {'$inc': {count: 1}}, {upsert: true}, function() {
            console.log('inc callback');
        });
    },

直接的函数调用,不存在异步,所以函数里面的

console.log('function inc');

会在for里面输出.在输出之后,会执行函数里面的代码:

this.update({name: name}, {'$inc': {count: 1}}, {upsert: true}, function() {
    console.log('inc callback');
});

注意,下面这条语句是异步函数里面的语句:

console.log('inc callback');

这条异步语句,会在数据库返回结果后执行。整个文件的其他代码类似

所以连起来整个文件的代码应该输出:

1000次 function inc
1000次 function dec
1次    function all

然后会输出

1000次 function inc callback
1000次 function dec callback
1次    function all callback

那么问题就出现了。在mongoskin里面会按照上面的顺序输出。而在mongoose里面会顺序输出:

1000次 function inc
1000次 function dec
1次    function all

这个是应该的,因为不存在异步。但是会乱序输出:

1000次 function inc callback
1000次 function dec callback
1次    function all callback

说明他的回调函数,是异步返回的,根据该语句的执行时间不同,返回的顺序不一样。

所以我上面的所有代码说明了,在异步回调函数的返回顺序这个问题上,mongoskin是顺序的,mongoose是乱序的。如果是顺序的,那么执行的数据库操作就是串行的。 我上面所有的内容都是根据表面内容的分析,可能不对。我猜测,仅仅是猜测,有可能是下面两个原因之一: 1 mongoskin 在处理异步回调的时候,有特殊的机制? 在这个特殊的机制里面有问题? 2 mongoose 有多个连接?每次操作自动从连接池里面分配一个连接和数据库交互,而mongoskin默认只使用了一个,需要手工管理多个连接?

我是从chrome dev tools的官方文档上看的。

this.update 这个方法是mongoskin自带的吗 还是mongo原生的呢

从你提供的代码来看,问题可能出在 mongoskinbind 函数的处理上。mongoskin 是一个较旧的 MongoDB 驱动库,它在处理异步操作时可能会有一些限制或问题。而 mongoose 则是一个更为现代和健壮的 MongoDB ORM 库,能够更好地处理并发操作。

mongoskin 中,bind 方法创建的对象方法默认不会并发执行。你可以尝试使用回调的方式来解决这个问题。以下是一个修改后的示例:

const db = require('mongoskin').db('localhost:27017/test', {safe: true});

db.bind('tag', {
    inc: function(name, callback) {
        console.log('function inc');
        db.collection('tag').update({name: name}, {'$inc': {count: 1}}, {upsert: true}, function() {
            console.log('inc callback');
            callback(null, 'done');
        });
    },
    
    dec: function(name, callback) {
        console.log('function dec');
        db.collection('tag').update({name: name}, {'$inc': {count: -1}}, {upsert: true}, function(error) {
            console.log('dec callback');
            callback(error, null);

            db.collection('tag').findOne({name: name}, function(error, item) {
                if (error) return callback(error, null);

                if (item && item.count <= 0) {
                    db.collection('tag').remove(item, function(error) {
                        if (error) return callback(error, null);
                    });
                }
            });
        });
    },
    
    all: function(callback) {
        console.log('function all');
        db.collection('tag').find().toArray(callback);
    }
});

for (var i = 0; i < 1000; i++) {
    db.tag.inc('电影', function() {});
}

for (var i = 0; i < 500; i++) {
    db.tag.dec('电影', function() {});
}

db.tag.all(function(err, data) {
    console.log('function all callback');
    for (var index in data) {
        console.dir(data);
    }
});

在这个示例中,我将 updatefindOne 等操作放在回调函数中,确保每个操作完成后才会执行下一个操作。这样可以避免由于 mongoskin 处理并发操作时可能出现的问题。

回到顶部