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 && item.count <= 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不是串行的。
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);
}
});
观察结果
多次运行上述代码,可以看到所有的 inc
和 dec
操作似乎是串行执行的,而不是并发的。这意味着 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
时,inc
和 dec
操作是并发执行的,而不是串行的。这表明问题确实出在 mongoskin
的处理方式上。
结论
mongoskin
在处理绑定方法时可能存在某种同步机制,导致并发操作表现得像是串行的。如果需要并发处理,建议考虑使用其他库如 mongoose
。
mark
大侠,请问您如何得知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原生的呢
从你提供的代码来看,问题可能出在 mongoskin
对 bind
函数的处理上。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);
}
});
在这个示例中,我将 update
和 findOne
等操作放在回调函数中,确保每个操作完成后才会执行下一个操作。这样可以避免由于 mongoskin
处理并发操作时可能出现的问题。