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函数),游标使用完,一定要显式将其关闭,否则会一直消耗服务器资源。
相对于一般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函数),游标使用完,一定要显式将其关闭,否则会一直消耗服务器资源。