mongoose中想用where a_ids in aArray 或者 b_ids in bArray能办到吗?
发布于 2年前 作者 shinka 1305 次浏览

请问我用mongoose的话,想用where a_ids in aArray 或者 b_ids in bArray 或者c_ids in cArray,我刚用$where试了下失败了,代码如下,希望帮忙看看怎么整比较好。

var line = "";
if(uids.length > 0){
  line += "createby.uid in [" + uids + "]";
}
if(gids.length > 0){
  line += " || createby.gid in [" + gids + "]";
}
if(tids.length > 0){
  line += " || createby.tid in [" + tids + "]";
}

message.find({}).$where(line).setOptions(optionObj).exec(function(err, messages){
  callback_(err, messages);
});
4 回复

你说的这个api上有的,你的用法已经很接近了。代码如下

message.find().where('createby.uid').in(uids).exec(function(err,messages){

});

另外有些编辑器会给你报错,说in是一个关键字,这个你可以忽略。 where错误的用法是

message.find().where('createby.uid',uids).exec(function(err,messages){

});

因为此时他仅仅只能把你拼装好的uids当作是一个值来与数据库的createby.uid做比较,他是不知道你是要做数组的exists比较的。 要使用多个where-in判断,他们之间的关系是and,因此可以直接连接写

message.find()
             .where('createby.uid').in(uids)
             .where('createby.gid').in(gids)
             .where('createby.tid').in(tids)
             .exec(function(err,messages){

});

但是如果他们之间的关系是or,也许你在想是不是要用如下代码

message.find()
             .where('createby.uid').in(uids).or()
             .where('createby.gid').in(gids).or()
             .where('createby.tid').in(tids)
             .exec(function(err,messages){

});

答案是错的,or后面只支持对象数组,因此不可以这么添加,但是非要用你这样的搜索怎么办?mongoose本身是提供了原生搜索方法的,查阅mongoose-api和mongodb-api,你甚至能发现很多方法相同或者配置项相同的单词,OK你没有看错,他们确实有很多共同点。直接告诉你答案吧,按照你的思路,代码如下

message
    .find()
    .or([
        {'createby.uid':{$in:[uids]}},
        {'createby.tid':{$in:[tids]}},
        {'createby.gid':{$in:[gids]}}
    ])
    .exec(function(err,messages){

    });

关键地方就是那个$in,记得官网有提过,这种写法是不安全的,他们也正在做改进,有些原生的写法是在api上被移除,但仍然可以使用,使用用风险,需要多注意。举个一般的例子,假设某个脑残程序员为了简单,未做任何处理,写了这样的查询代码

var id = req.param.id;
dao.find({id:id},function(err,docs){

});

看似没问题吧,有问题,数据的安全性有可能被暴露,预想提交的数据是data:{id:'123'},但是实际可能提交的数据是data:{id:{$ne:'123'}}。ok,这就意味着你的程序会查询所有id不是123的doc,数据的安全性被攻破,而且数据量过大的时候会导致服务器崩溃。 要等解决这种问题,就只能等官方进一步优化,移除配置项。

大神! 太感谢你了! 早上上班能看到这个真是叫人无比激动啊! 哈哈 谢啦 mongoose的where(“createby.uid”).in(uids)这个用法我也考虑过,但是想想要实现会比较麻烦,然后就想试试mongoose提供的$where的方式,可惜失败了。但是没有想到最后第二段你提到的那种原生态方式。另外有一个疑问,我也知道dao.find({id: id})这种写法不好,但是为啥实际提交的数据会变成data:{id:{$ne:’123’}}呢? 求大神指点

假设这个脑残的程序员想解决这个问题,需要怎么做呢?

@shinka @bml3i

首先,我们一定期望前端如果ajax提交的是对象,那么后端req.param得到的也一定是对象而不是字符串,即便属性是字符串,我们依然希望格式是对的,例如:

//前端提交
$.ajax({
    url:'user_detail.html',
    type:'post',
    dataType:'json',
    data:{
        id:'123'
    }
});
//后端查询
var param = req.param;//打印的结果是{id:"123"},而且这样的param是直接可用的对象

由于前端传的对象对于后端是可以不用转换直接可用的,那么此时就要注意,如果我拦截参数data:{id:'123'},将其转换为mongodb(假设我猜测你的数据库是mongodb)参数对象例如data:{id:{$ne:'123'}},那么后台的查询就会失去安全性或者因为查询量过大导致服务器负载过高。当然,这是使用了一种参数化组件,即前端怎么传参数,后端就怎么接受,接受到的参数是实际可用的。我在‘[问题]POST提交对象到后台如何转换?1’里有讲过这个,因为我以前是做java的,所以很喜欢这样的提交方式。要想避免这样的方式,显然是要从脑残的阶段变的稍微睿智一些,熟悉mongoose的一些查询参数和原理,对于这个案例,只要将post提交改为post提交即可,提交参数通过字符串拼接到url后面即可,这样id被传送到后台依然是字符串,而不是对象了。但是这并不能解决实际问题,通过拦截ajax提交实现注入的方式,甚至浏览器的调试工具都能绕过js将注入对象提交到后台,所以应该在后台去做数据安全性的验证。 如果你没有使用前后台通用对象传递,那么意味着你前端传递到后台的都是字符串,这将面临着巨大的解析困难,如果你不怕困难,一个个的解析倒是挺不错的,也能对一些关键字做拦截。 总结起来,简单的说要注意以下几点: 1.前端选择适合的提交方式 2.后端要对数据进行验证 3.执行的操作要选择适合的(例如上例将find({id:’123’})修改为findById(‘123’)会比较妥) 以上只是我看了mongoose-api之后的一点点程序异常流的注意意识,并没有形成系统,而且我现在暂时没有考虑这些复杂繁多的安全验证,我采用的是分层开发,核心业务我就当作是全部数据通过的情况,最后项目完成的时候,我会在旁路业务中添加同意的数据安全验证模块,来避免以上的一些可能,当然注入的情况还有很多,需要更多的学习时间和实践。也希望大家遇到什么问题或者想法都贡献出来分享,大家一起学习一起进步呀。

回到顶部