刚从mysql等关系数据库中转过来,关于mongodb的关系处理有点不明白: 比如说我有一个collection存放文章(id,内容,作者,分类id),另一个collection存放文章分类(id,类名,描述),我如果要query(文章内容、作者、分类名)用mysql之需要一个一句sql就可以,如果用mongodb怎么处理? 是不是需要先查询文章collection,再从回调函数中查询分类collection,再去渲染页面?
####再更新 看了下本站的源代码,发现其中主题列表的实现方法真的是–如果按以前的观点–真的是要用令人发指来形容了: 首先获取十几个主题的id,然后对其for循环,拿着id去findOne,找到后回调中去查用户名、标签,这一系列要循环十几次。 mongodb这样做性能损失大么? 以前做sqlserver、mysql,那时候的原则以尽量少的数据连接,尽量少的sql语句完成一次查询,mongo下这些可以颠覆吗?
外键在mogodb中是DBRef 啊,就是引用
用mongodb就要多用反范式,多数据冗余吧,你这么查没问题的。
单个的这么查应该没什么问题,但是如果我要实现一个文章列表(有几十片文章要显示分类),那怎么办?
@justfly 有2种方法可以做到。 1、就是1楼所说的dbref,像mongodb-native这类nodejs连接可以自动解除dbref引用。 伪代码如下: var child = {‘name’ : ‘child’, ‘parent’ : new DBRef(“test_resave_dbref”, parent._id)}; collection.insert(child, {safe : true}, function(err, objs) {}) collection.findOne({‘parent’ : new DBRef(“test_resave_dbref”, parent._id)})
2、利用$in来批量匹配 思路:先查出这几十片文章的分类id,然后去分类集合中匹配分类名。 var cataArray = [‘分类id1’, ‘分类id2’, ‘分类id2’, ‘分类id3’] collection.find({_id:$in:cataArray})
希望对你有帮助吧,2种方法效率差不多
我是习惯找到分类id,放到数组里面,然后用$in查询。 假设文章在articles集合,分类在categories集合。在category文档中,名称保存在名为name的字段中。分类id在article文档中字段名为cateId,我们需要查询到分类名称后赋值给article文档中的cateName字段。 操作都差不多,变的就是集合名和字段名,可以写个通用函数来处理这个过程。
@snoopy 分类和文章是一对多的关系,一篇文章有一个分类,一个分类下有若干文章。这种情况怎么办,我不知道$in的方法是怎么实现query(文章内容、作者、分类名)的。 collection.find({_id:$in:cataArray})查出来的不就是全部的分类?麻烦给个示例代码看看,不胜感激
@imzshh 你的假设正是我的需要, 分类和文章是一对多的关系,一篇文章有一个分类,一个分类下有若干文章。求具体$in的实现方法,感谢:)
@snoopy 你说的方法大概是这样吧,但是当catearray有重复时查不出来的:
function get_category_name(query,cb){
Article.find(query,{category_id:true,},function(err,ids){
var id_array=[];
for (var i = 0; i < ids.length; i++) {
id_array[i] = ids[i].category_id;
};
Category.find({_id:{$in:id_array}},{name:true},function(err,category_names){//此处若id_array有重复项,比如[1,1]就职能查出一个结果
return cb(category_names);
});
});
};
这样就行不成和文章数组对应的分类名数组
@justfly 对啊,你这样就查出了所有你想要的分类id和名字了,然后自己手动匹配吧。比如你可以把查询出的数组转换为对象,伪代码如下:
var cataObj = {};//存放分类的id-name对象
cataRes.forEach(function(cat){//分类查询结果
cataObj[cat._id]=cat.name
})
articleRes.forEach(function(art){//文章查询结果
art.cataName = cataObj[art.cataId]
})
这样就给你的查询结果articleRes每个都添加了art.cataName属性了
@snoopy 明白了,已经实现了!:)无论多少文章只要查询两次数据库就能搞定
@justfly nosql不是no-sql,是not only sql,哈哈~是用上面的那个方法吗?还是有更好的,分享下吧
exports.get_all_categories = function(req,res,next){
var category_array=new Array();
Category.find({},function(err,docs){
if(err)
return next(err);
for (var i = 0; i < docs.length; i++) {
category_array[i]={id:docs[i]._id,name:docs[i].name};
category_array[docs[i]._id] = docs[i].name;
};
res.locals.categories=category_array;
return next();
});
}
核心方法就是这样,把所有分类(id,name)查出来做成数组,这个数组是php式的,既有key=>value,也有index=>value,放到内存里,以后不论用for循环查还是要输出文章分类名称,都能查出