Mongodb

Mongodb和mongoose模糊查询

月盾

需求说明:在mongdb中使用模糊查询,就像sql中的like查询,在where条件中使用模糊匹配,当然最重要的是需要模糊查询的字符串是动态传入的

以一篇文章为例,content字段为文章内容,我们要查询文章内容中包含Nodejs关键字的文章

mongodb中查询

select * from articles where content like '%Nodejs%';
db.articles.find( { content: /Nodejs/i } )
Article.find({ content: /Nodejs/i}, function (err, docs) {});

这种写法是一种简写操作,需要注意的是不能带双引号,带了双引号就成了字符串。但是这种写法是用/包裹了一个字符串类型的关键字,在实际程序是动态传入的,比如:

var a="Nodejs" ;
Article.find({ content: /a/i}, function (err, docs) {});

此时会把"a"当做要查询的关键字而不是"Nodejs",所以这时还是需要用到完整的查询方式,就是使用$regex关键字,还有$options选项

var text = 'Nodejs';//动态传入的变量
Article.find({ content: { $regex: text, $options: 'i' }}, function (err, docs) {});

$options选项值:

  • i 大小写不敏感
  • m $regex包含正则^,$符号的表达式
  • x 忽略空格
  • s 允许逗点匹配所有字符串

其实$regex就是正则表达式的写法

查找数组中的字段:

contacts:{
    [
        {
            address: "address1",
            name: "张三"
        },
        {
            address: "address2",
            name: "李四"
        },
        .....
    ]
}

可以通过db.collection.find({'contacts.name':{$regex:'张'}})获得

Mongodb和mongoose聚合查询

月盾

mongdb查询某一字段sum值

需求说明:articles有一个字段pv记录了该文章的访问量,现在要统计所有文章访问量,类似于sql中的sum统计

mongodb中查询

select sum(pv) from articles;
db.articles.aggregate([{$group:{_id:null,pv:{$sum:"$pv"}}}]);
结果:{ "_id" : null, "pv" : 2 }

select sum(pv) from articles where createDate <= '2016-10-20';
db.articles.aggregate([{$match:{createDate:{$lte:"2016-10-20"}}},{$group:{_id:null,pv:{$sum:"$pv"}}}]);
结果:{ "_id" : null, "pv" : 9 }

select sum(pv) from articles where category = 'Nodejs';
db.articles.aggregate([{$match:{category:"Nodejs"}},{$group:{_id:null,pv:{$sum:"$pv"}}}]);
结果:{ "_id" : null, "pv" : 7 }

需要注意$match$group的顺序,反了是不行的,因为这是Aggregation Pipeline(管道流)

mongoose实现方式,与上面sql的顺序对应:

Article.aggregate({ $group: { _id: null, pvCount: { $sum: '$pv' }}}, function(err, doc) {
    console.log("1", doc);
});
Article.aggregate([{$match:{createDate:{$lte:"2016-10-20"}}},{$group:{_id:null, pvCount:{$sum:"$pv"}}}], function(err, doc) {
    console.log("2", doc);
});
Article.aggregate([{$match:{category:"Nodejs"}},{$group:{_id:null, pvCount:{$sum:"$pv"}}}], function(err, doc) {
    console.log("3", doc);
});
1 [ { _id: null, pv: 25 } ]
2 [ { _id: null, pv: 9 } ]
3 [ { _id: null, pv: 7 } ]

参考文档:

BAE上连接mongodb每隔十多小时就不能连接的问题(二)

月盾

前段时间写了《BAE上连接mongodb每隔十多小时就不能连接的问题(一)》之后暂时的解决了连不上的问题,每隔十小时重启一次,但是这个方法却没有彻底解决问题,偶尔还会出现三四小时就连不上,实在搞不懂问题到底出在哪,到底是bae的mongodb的问题还是mongoose中间件的问题,现象是有做open操作,但是却没有open事件发出,那么我想是不是mongoose存在bug,翻看了源码也没看出来个所以然,不过大概是觉得要重新打开需要保证连接已经关闭的,那么干脆在监听到error事件时就将状态直接改为disconnected,反正是要调用db.close()方法进行关闭连接的,可能close()方法不好使,没有完全关闭,如果我手动将状态设为disconnected,close方法中也会判断是否是这个状态,如果是就直接返回,省的多走其他步骤了。不过这样一来就不会有close事件发出了,根据我所写代码的逻辑,那就不会调用open()方法了,但实际情况确实程序可以正常运行,说明已经重连上了,原来在代码中添加了这个属性:

Js代码 :

var opts = { 
db: { 
  native_parser: true  
}, 
server: { 
  poolSize:4, 
  auto_reconnect: true  
}, 
user: username, 
  pass: password 
};

上面的红色字体,只能说是可能这个参数起作用了。

不过由此看来,auto_reconect这个参数要起作用必须是在连接断开的情况下,说明close()方法有时候并没有完全断开连接。

mongoose实现翻页

月盾

随着吐槽的内容越来越多,单页显示就显得不够文雅了,分页功能是一个完整系统必备的。所以就决定加上这个功能,不过分页实现起来并不容易,找了下前辈们的资料,感觉都很复杂,所以还是实现一个简单翻页好了,就是只有上一页,下一页这样简单的功能。

首先看下mongoose API,find方法源码:

Model.find = function find (conditions, fields, options, callback){
if("function"==typeof conditions){
    callback = conditions;
    conditions ={};
    fields = null;
    options = null;
}elseif("function"==typeof fields){
    callback = fields;
    fields = null;
     options = null;
 }elseif("function"==typeof options){
     callback = options;
     options = null;
 }
 // get the raw mongodb collection object
   var mq =newQuery({}, options,this,this.collection);
   mq.select(fields);
 if(this.schema.discriminatorMapping &amp;&amp; mq._selectedInclusively()){
     mq.select(this.schema.options.discriminatorKey);
 }
 return mq.find(conditions, callback);
 };

其中有4个参数,find(条件,需要查询的字段,选项,回调),这样看着太抽象,来一段实际应用的代码:

router.get("/admin/blogList", function(req, res) {  
    var user = req.session.user;  
    var pageIndex = 1;  
    var pageSize = 5;  
    pageIndex = req.query.pageIndex == undefined ? pageIndex  
            : req.query.pageIndex;  
    pageSize = req.query.pageSize == undefined ? pageSize : req.query.pageSize;  
    Blog.find({}, null, {  
        sort : {  
            "_id" : -1  
        },  
        skip : (pageIndex - 1) \* pageSize,  
        limit : pageSize  
    }, function(err, docs) {  
        if (err)  
            res.send(err.message);  
        res.render("admin/bloglist", {  
            blogList : docs,  
            user : user,  
            pageIndex : pageIndex,  
            pageCount : docs.length  
        });  
    });  
});

其中Blog.find({},null,{sort:{"_id":-1}, skip :( pageIndex -1)* pageSize, limit : pageSize },function)
这一段第一个参数为空,意思查询所有,第二个参数null,查询所有字段,第三个参数有倒序,分页。
然后就是页面上两个翻页按钮: