mongodb学习笔记2,mongodb的查询

mongdb定位是介于关系型数据库与非关系型数据库之间
相对于一般nosql数据库,mongodb拥有强大的查询能力
语法设计上是参照了sql的语法

查询集合所有文档
db.account.find()
ps:db.account.find不加括号时,返回find命令的源码

简单条件查询
db.account.find({"userName":"bbs10"})

多值匹配条件查询,类似“条件1 and 条件2”
db.account.find({"userName":"bbs10","passwd":"ddd"})

指定返回某些键
1表示返回该属性,0表示不返回该属性
db.account.find({},{"_id":1,"userName":1})
db.account.find({},{"passwd":0})

只返回userName,不返回_id(默认会返回_id)
db.account.find({},{"userName":1,"_id":0})

复合条件查询
比较操作符
lt,lte,gt,gte,ne
 <, <=, >, >=,!=

先定义一个start
start=new Date()
查询大于start的文档
db.account.find({"createTime":{"$gt":start}})

组合使用查询年龄大于30小于40
db.account.find({"age":{"$gt":30,"$lt":40}})

年龄不等于30的文档
db.account.find({"age":{"$ne":30}})

$in查询,类似于sql中的in
db.account.find({"age":{$in:[30,32]}})

$nin查询,类似于 not in
db.account.find({"age":{$nin:[30,32]}})

$or  或查询,可多键查询
查询userName为bbs10或者age为32的文档
db.account.find({"$or":[{"userName":"bbs10"},{"age":32}]})

组合起来用
db.account.find({"$or":[{"userName":"bbs10"},{"age":{"$in":[30,32]}}]})

$not运算符,取非,可以用于任何查询条件上
db.account.find({"age":{"$not":{"$nin":[30,32]}}})

$mod取模运算,查询用5去除余数为0的文档
db.account.find({"age":{"$mod":[5,0]}})

高级查询规则
null不仅匹配自身,还匹配不存在
该语句查出了为null值的文档和不包含createTime字段的文档
db.account.find({"createTime":null})

要结合$exist才能准确查出属性为null的文档
db.account.find({"createTime":{"$in":[null],"$exists":true}})
写程序时null值处理要谨慎,否则容易出bug

正则表达式
db.account.find({"userName":/bbs10/i})
带前缀正则表达式查询性能最好
db.account.find({"userName":/^bbs10/i})

查询数组
先插入数组
db.food.insert("_id":1,["apple","banana","peach"])
db.food.insert("_id":2,["apple","watermelon","orange"])
db.food.insert("_id":3,["cherry","banana","apple"])

单元素匹配
数组里任何一个匹配,则算条件符合
db.food.find("fruit":"apple")
可以查出全部123

多元素匹配,既有apple又有banana
$all
db.food.find("fruit":{$all:["apple","banana"]})
查到1,3

数组下标从0开始,用数组下标指定位置查询
查询下标为2的值是apple的文档
db.food.find({"fruit.2":"apple"})
查到3

$size查询指定数组长度的数组
db.food.find({"fruit":{"$size":3}})

查询内嵌文档
先插入一些数据
db.account.insert("userName":{"first":"joe","last":"schmoe"},"age":35)
db.account.insert("userName":{"first":"tom","last":"schmoe"},"age":35)

完全匹配查询
db.account.find("userName":{"first":"joe","last":"schmoe"})

用点表示法改变文档
db.account.update({"$set":{"userName.passwd":"ddd"}})

点表示法查询,不受文档数据模式改变影响
db.account.find({"userName.first":"joe","userName.last":"schmoe"})

增加数组元素
db.account.update({},{"$push":{"comments":{"author":"joe","score":3,"comment":"test"}}})
db.account.update({},{"$push":{"comments":{"author":"tom","score":5,"comment":"test"}}})
查询作者为joe并且得分超过5分的文档,可惜下面这条查出来的是作者是joe或者得分为5,即单个匹配
db.account.find({"comments.author":"joe","comments.score":{"$gte":5}})
正确做法,采用$elemMatch对内嵌文档多键匹配
db.account.find({"comments":{"$elemMatch":{"author":"joe","score":{"$gte":5}}}})

where查询,不同于sql中的where
查出存在键值相等的文档(比如{"_id":"1","apple":4,"banana":4})
db.food.find({"$where":function(){
    for(var current in this){
        for(var other in this) {
            if (current != other && this[current]==this[other]){
                return true;
            }
        }
    }
    return false;
}})
ps:上面function是javascript语法。

尽量使用键/值对查询方式,不是万不得已逼急了请不要使用where查询。
where查询无法使用索引,并且文档要从bson转成javascript对象,所以查询速度非常慢。

游标操作
先造数据,插入100个文档
for(i=0;i<100;i++){db.c.insert(x:i);}

定义游标
var cursor=db.c.find()
此时find不会马上执行
游标迭代器:
while(cursor.hasNext()) {
    obj=curosr.next()
}
此处和jdbc很相似,游标可以理解为一个指针,客户端执行cursor.hasNext()时,查询发往服务器,执行真正查询,shell会获取前100个结果或者4M数据(两者较小者)返回。

java代码
/**
 * 批量查询账号
 */
public Account[] getAccounts(String[] nameArray) {
    List<Account> result = new ArrayList<Account>();
    DBCollection coll = connection.getCollection(COLLECTION_ACCOUNT;
    QueryBUilder queryBuilder = QueryBuilder.start();
    DBObject query = queryBuilder.put("userName").in(nameArray).get();
    DBCursor cursor = coll.find(query);
    try{
        while(cursor.hasNext()){
            DBObject obj = cursor.next();
            Account a = new Account();
            a.fromDBObject(obj);
            result.add(a);
        }
    }finally{
        if (cursor!=null)
            corsor.close();
    }
}

游标用来限制结果数据,取前5个
db.c.find().limit(5)
跳过匹配的文档,跳过前5个
db.c.find().skip(5)

排序:sort用一个对象作为参数,键值对表示,键对应文档键名,值表示排序方向。1升序,-1降序
db.f.find().sort({x:-1})
多键复合排序
db.account.find().sort({userName:1,age-1})

游标分页查询,每页显示20条数据,查询第二页
db.c.find({"y":"post"}).limit(20).skip(20).sort({"x":1})
用skip跳过文档是可行的,但是数量过多就会变慢


不用skip的分页:
java代码
/**
 * 分页查询(利用id从小到大的排序的原理,注意id一定要升序排列)
 * pageNum 每页条数
 * lastID 上一页最后的_id值
 */
public LinkedList<LoginToken> getPage(int pageNum,String lastID) {
    DBCollection coll = connection.getCollection(COLLECTION_NAME);
    QueryBuilder queryBuilder = QueryBuilder.start();
    DBObject query = queryBuilder.put("_id").greaterThan(lastID).get();
    DBObject orderBy = new BasicDBObject("_id",1);//根据_id升序排列
    DBCurrsor cursor = coll.find(query).sort(orderBy).limit(pagenum);
    Linkedlist<LoginToken> result = new LinkedList<LoginToken>();
    while(cursor.hasNext()){
        DBObject obj=cursor.next();
        LoginToken token = new LoginToken();
        token.fromDbObject(obj);
        result.add(token);
    }
    return result;
}
ps: mongodb中_id会默认建索引。


游标内幕
每一个客户端游标在服务端都会对应,游标消耗内存和其他资源,要尽快合理释放。
游标遍历完或客户端发消息终止时释放游标。
游标在客户端不在作用域(java方法体内),驱动会向服务器发送消息销毁游标。
超时销毁机制,游标即使在客户端作用域内,但是10分钟不用,也会自动销毁。
关闭游标超时销毁机制(使用驱动immortal函数),游标使用完,一定要显式将其关闭,否则会一直消耗服务器资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值