循环进行mongoose操作为什么总是重复最后一条?见鬼!Nodejs [CLOSED]
循环进行mongoose操作为什么总是重复最后一条?见鬼!Nodejs [CLOSED]
//我这里是想先查询数据库是否已经保护這条数据 如果没有的话 后再进行保存 防止重复
TweetDAO.prototype.save = function (objs, callback) {
var const_count = 0;
for(var obj in objs){
console.log(obj+" : “+ objs[obj].id);
var temp = objs[obj];
findOneById(objs[obj].id,function(findResult,query){
console.log(“id:”+query + " 是否有数据:”+(findResult!= null) );
if(findResult =="" || findResult ==null){
var instance = new Tweet(temp);
instance.save();
}
});
}
};
var findOneById = function(query,callback) {
Tweet.findOne({id:query}, function(err,data){
console.log(data);
callback(data,query);
});
}
但是每次我发现 每次插入全部都是重复最后一条啊!
你遇到的问题是因为异步操作的回调函数在循环结束后才被执行,导致所有的 findOneById
操作都使用了相同的 obj
值。为了解决这个问题,你可以使用 async
库来管理异步操作。
示例代码
首先,安装 async
库:
npm install async
然后修改你的代码:
const async = require('async');
TweetDAO.prototype.save = function (objs, callback) {
const tasks = objs.map((obj) => {
return (done) => {
console.log(obj.id);
findOneById(obj.id, (findResult) => {
console.log("id:" + obj.id + " 是否有数据:" + (findResult != null));
if (findResult == null) {
const instance = new Tweet(obj);
instance.save(done);
} else {
done();
}
});
};
});
async.series(tasks, callback);
};
var findOneById = function (query, callback) {
Tweet.findOne({ id: query }, function (err, data) {
console.log(data);
callback(data);
});
};
解释
-
使用
async
管理异步操作:async.series
方法可以确保所有任务按顺序执行,并且每个任务完成后才会开始下一个任务。
-
映射对象到任务数组:
- 使用
objs.map
将每个对象映射成一个任务函数,这样每个任务都有自己的上下文,不会被其他任务覆盖。
- 使用
-
异步回调处理:
- 在
findOneById
的回调中,如果找到结果,则直接调用done()
结束当前任务;如果没有找到结果,则创建新的Tweet
实例并保存,保存成功后调用done()
结束任务。
- 在
通过这种方式,你可以确保每个对象的操作是独立的,并且按顺序执行,避免了重复最后一条数据的问题。
问题出在这里 var instance = new Tweet(temp);
你这里取的temp 永远都是objs里的最后一条记录 应为你的回调函数是最后执行的,这行循环早就执行完了,所以此时你再去取 temp的值肯定就是最后一条啦
了解一下闭包吧
这个如何改进了?麻烦告诉一下。
你的问题在于异步操作的控制流程。你使用了 findOneById
方法来查找数据,但因为这是一个异步操作,所以 for
循环不会等待 findOneById
完成后再继续执行。这导致所有的 findOneById
操作几乎同时完成,而此时循环可能已经完成了多次,因此最后保存的数据总是最新的 obj
。
你需要确保每个 findOneById
操作完成后才能继续下一个。可以使用 async
库来处理这种异步操作的顺序问题。下面是一个修改后的代码示例:
const async = require('async');
TweetDAO.prototype.save = function (objs, callback) {
async.eachSeries(objs, (obj, cb) => {
console.log(obj + " : " + objs[obj].id);
var temp = objs[obj];
findOneById(objs[obj].id, (findResult) => {
console.log("id:" + temp.id + " 是否有数据:" + (findResult != null));
if (findResult == "" || findResult == null) {
var instance = new Tweet(temp);
instance.save(cb); // 使用cb来处理保存完成后的回调
} else {
cb(); // 数据已存在,直接回调
}
});
}, callback); // 所有对象处理完成后调用callback
};
var findOneById = function (query, callback) {
Tweet.findOne({ id: query }, function (err, data) {
console.log(data);
callback(data ? true : false); // 简化返回值,如果找到数据返回true,否则返回false
});
};
解释:
async.eachSeries
:它会按顺序依次处理数组中的每个元素,并在当前元素处理完成后才会开始处理下一个。instance.save(cb)
:在保存实例后调用回调函数,以确保异步操作的顺序正确。- 简化返回值:在
findOneById
中,我们简化了返回值逻辑,以便于判断数据是否存在。
这样,你可以确保每个 findOneById
操作完成后才会进行下一步,从而避免所有操作都处理同一个对象的问题。