我设计了两个collection,一个是分类的collection,另一个是分类下对应图片的collection,分类有‘推荐’这个字段,每张图片都有一个对应的分类字段。现在我需要将所有分类为推荐状态下的图片查询出来,并在页面上显示为列表,每个列表显示分类名和其所对应的图片,我是这样做的。但现在遇到的问题是,经常刷新页面的时候,显示的图片跟分类名称对应不上,总是串位,想知道这是怎么一回事?
‘’’'Picture.prototype.getByRecommondCate = function(callback){ var piclist = []; mongodb.open(function(err,db){ if(err){ return callback(err); } db.collection(‘categorys’,function(err,collection){ if(err){ mongodb.close(); return callback(err); }
collection.find({
isRecommend:"true"
}).toArray(function(err,cates){
if(err){
mongodb.close();
return callback(err);
}
db.collection('pictures',function(err,collection){
if(err){
mongodb.close();
return callback(err);
}
for(var i = 0;i<cates.length;i++){
collection.find({
category:cates[i].name
}).limit(20).toArray(function(err,pics){
if(err){
mongodb.close();
return callback(err);
}
piclist.push(pics);
if(piclist.length == cates.length){
callback(null,cates,piclist);
}
})
}
})
})
})
})
}’’’’
代码太多了,看不清楚。另外建议重新设计下你得数据模型,你这个需求用一张collection就能搞定
@jingsam 请问下怎么设计会比较好呢?
首先你的数据存储结构(many to many)符合你的需求(注1),其次我不确定你上面贴的逻辑有返回值或正确的返回值,最后是一个for + 异步 的一个小误区;ok, 问题1:先确认下你的callback函数只有在piclist的长度等于类型长度时才返回,同时类型限制条件是被推荐,可以是很多很多。。。而图片列表限制不能超过20,换句话说只有恰巧你的类比表中有20个被推荐的,而且恰好该类别有20张图片才会有返回,其余情况下都是无返回的状态; 问题2:其实是一个经典的for + 异步的坑,建议通过下面的列子说明:
var arr = [1,2,3];
for(var i in arr) {
setImmediate(function () {
console.log('item is', arr[i]);
});
}
for是同步执行,在遇到setImmediate等异步函数时并不会等待异步执行完,实际上是打印了三次arr[i]而由于异步的原因,并不会立即输出,而是等待for同步任务全部完成后才会进入下一个事件循环,而此时arr[i]已经是数组的最后一个元素了,所以可以看到打印出来的是三个3;当然还有一个坑是js数据类型引起的,比如
var arr = [1,2,3];
for(var i in arr) {
var foo = arr[i];
setImmediate(function () {
console.log('item is', foo);
});
}
有的同学会认为这样就可以达到遍历输出arr的效果了,其实这里要引入js的基础数据类型的概念,arr,Object等都不属于js基础数据类型,所以在内存中均以引用的形式存在,略懂c的同学都知道,将一个引用的地址传递给一个变量名,实质上仍旧是最后一次修改后的数据,仍旧是最后一个元素; 为了解决该问题,可以引入异步控制流的方式(当然并不一定使用async,这里只是一个demo),比如这样:
var arr = [1,2,3],
async = require('async');
async.each(arr, function (item, cb) {
setImmediate(function () {
console.log('item is', item);
});
}, function (err) {
if (err) console.error('err is', err);
})
注1:考虑到后期可能出现很多分类对应很多图片的场景,不建议使用聚合的存储结构,虽然一张表可以同时存储分类以及下属图片,但可能出现很多问题,比如后期图片太多时超过16M限制;比如同一张图片可能会有不同的分类属性,冗余度就很高;执行更新操作时因为聚合结构过深效率很低等;
@haozxuan 后来我用一个递归的方式替代了for循环。但是隐约感觉还会有坑的存在,准备替换成async这种方式去处理了