//查找User表所有信息-查
BmobQuery *yonghu = [BmobQueryqueryWithClassName:@"User"];
[yonghu findObjectsInBackgroundWithBlock:^(NSArray *array,NSError *error) {
for (BmobObject *obj in array) {
//打印playerName
NSLog(@"obj.user_name = %@", [obj objectForKey:@"user_name"]);
NSLog(@"obj.user_password = %@", [obj objectForKey:@"user_password"]);
// 打印objectId,createdAt,updatedAt
NSLog(@"obj.objectId = %@", [obj objectId]);
NSLog(@"obj.createdAt = %@", [obj createdAt]);
NSLog(@"obj.updatedAt = %@", [obj updatedAt]);
//添加到user表中-增
BmobObject *test1 = [BmobObjectobjectWithClassName:@"User"];
[test1 setObject:_newyonghuming.textforKey:@"user_name"];
[test1 setObject:_newmima.textforKey:@"user_password"];
[test1 setObject:userIconforKey:@"user_icon"];
[test1 saveInBackgroundWithResultBlock:^(BOOL isSuccessful,NSError *error) {
if (error==nil)
{
注册成功!
}
else{
注册失败!
}
查询
查询单条数据
在某些情况下,如果知道某条数据的objectId,而且想得知该条数据的内容,可以使用BmobQuery检索得到一个完整的BmobObject:
//查找GameScore表
BmobQuery *bquery=[BmobQuery queryWithClassName:@"GameScore"];
//查找GameScore表里面id为0c6db13c的数据
[bquery getObjectInBackgroundWithId:@"0c6db13c" block:^(BmobObject*object,NSError*error){
if(error){
//进行错误处理
}else{
//表里有id为0c6db13c的数据
if(object){
//得到playerName和cheatMode
NSString*playerName=[object objectForKey:@"playerName"];
BOOL cheatMode=[[object objectForKey:@"cheatMode"] boolValue];
NSLog(@"%@----%i",playerName,cheatMode);
//打印objectId,createdAt,updatedAt
NSLog(@"object.objectId = %@",[object objectId]);
NSLog(@"object.createdAt = %@",[object createdAt]);
NSLog(@"object.updatedAt = %@",[object updatedAt]);
}
}
}];
查询多条数据
在某些情况下,当需要查询表中多条元素的时候,可以直接使用findObjectsInBackgroundWithBlock函数获取查询结果,默认100条。
BmobQuery *bquery=[BmobQuery queryWithClassName:@"GameScore"];
//查找GameScore表的数据
[bquery findObjectsInBackgroundWithBlock:^(NSArray*array,NSError*error){
for(BmobObject*objin array){
//打印playerName
NSLog(@"obj.playerName = %@",[obj objectForKey:@"playerName"]);
//打印objectId,createdAt,updatedAt
NSLog(@"obj.objectId = %@",[obj objectId]);
NSLog(@"obj.createdAt = %@",[obj createdAt]);
NSLog(@"obj.updatedAt = %@",[obj updatedAt]);
}
}];
这里需要注意的是:
1.默认情况下,系统实际上并不会返回所有的数据,而是默认返回10条数据记录,你可以通过setLimit方法设置返回的记录数量。更多细节可点击查看查询一节中的分页查询。
2.当查询的是用户表这种系统表的时候,返回的是BmobUser的数组,设备表,角色表也是这样的。
3.查询用户表,设备表、角色表为:
BmobQuery *bquery=[BmobUser query];//用户表
BmobQuery *bquery=[BmobInstallation query];//设备表
BmobQuery *bquery=[BmobRole query];//角色表
条件查询
比较查询
当然了,在大多数情况下,开发者还是会通过特定的条件来筛选,过滤某些数据来进行查询。BmobQuery也提供了对应的查询方法。
如果要过滤特定键的值可以使用- (void)whereKey:(NSString *)key notEqualTo:(id)object。比如需要查询playerName不等于”小明”的数据时可以这样写:
当然,你也可以在你的查询操作中添加多个约束条件,来查询符合要求的数据。
BmobQuery *bquery=[BmobQuery queryWithClassName:@"GameScore"];
//添加playerName不是小明的约束条件
[bquery whereKey:@"playerName" notEqualTo:@"小明"];
各种不同条件的比较查询,还有
各种不同的比较查询:
[bquery whereKey:@"age" lessThan:[NSNumber numberWithInt:18]];//age小于18
[bquery whereKey:@"age" lessThanOrEqualTo:[NSNumber numberWithInt:18]];//age小于或等18
[bquery whereKey:@"age" greaterThan:[NSNumber numberWithInt:18]];//age大于18
[bquery whereKey:@"age" greaterThanOrEqualTo:[NSNumber numberWithInt:18]];//age大于或等于18
这里有点需要注意的是
时间搜索的话,等于的情况因为服务器是精确到微秒值,所以比较的值要加1秒。
子查询
如果你想查询匹配几个不同值的数据,如要查询“小明”,“小红”,“小白”三个人的信息是,可以使用
-(void)whereKey:(NSString*)key containedIn:(NSArray*)array;
函数,如下面所示:
[bquery whereKey:@"playerName" containedIn:[NSArray arrayWithObjects:@"小明",@"小红",@"小白",nil]];
如果是关联关系,直接在数组里面填写objectId即可,如下
[bquery whereKey:@"author" containedIn:@[@"063a2d739e",@"b97ca382c3"]];
相反,要排除这几个人的信息可以用
-(void)whereKey:(NSString*)key notContainedIn:(NSArray*)array;
函数,如下所示:
[bquery whereKey:@"playerName" notContainedIn:[NSArray arrayWithObjects:@"小明",@"小红",@"小白",nil]];
列值是否存在
其他的约束条件有
//设置查询中该字段是有值的结果
-(void)whereKeyExists:(NSString*)key;
//设置查询中该字段是没有值的结果
-(void)whereKeyDoesNotExist:(NSString*)key;
例如:
//查询表中score列有值的数据
[bquery whereKeyExists:@"score"];
//查询表中score列没有值的数据
[bquery whereKeyDoesNotExist:@"score"];
模糊查询
对字符串值的模糊查询 比如查询包含字符串的值,有几种方法。如下:
//使用正则表达式查询
-(void)whereKey:(NSString*)key matchesWithRegex:(NSString*)regex;
//查询以特定字符串开头的值
-(void)whereKey:(NSString*)key startWithString:(NSString*)start;
//查询以特定字符串结尾的值
-(void)whereKey:(NSString*)key endWithString:(NSString*)end;
注:模糊查询只对付费用户开放,付费后可直接使用。
分页查询
有时,在数据比较多的情况下,你希望查询出的符合要求的所有数据能按照多少条为一页来显示,这时可以使用limit方法来限制查询结果的数据条数来进行分页。默认情况下,Limit的值为100,最大有效设置值1000(设置的数值超过1000还是视为1000)。
bquery.limit=3;//限制得到的结果条数为3条
在数据较多的情况下,在limit的基础上分页显示数据是比较合理的解决办法,skip属性可以做到跳过查询的前多少条数据来实现分页查询的功能。默认情况下Skip的值为0。
bquery.skip=3;//跳过3条数据
排序
对应数据的排序,如数字和字符串,可以使用升序或降序的方式来控制查询数据的结果顺序:
// 升序
-(void)orderByAscending:(NSString*)key;
// 降序
-(void)orderByDescending:(NSString*)key;
例如,分数由高到低的排序可以写成
[bquery orderByDescending:@"score"];
当需要组合排序的时候可以这样处理
//先按照年龄升序排序,年龄一样再按照更新时间降序排序
[bquery orderByAscending:@"age"]
[bquery orderByDescending:@"updatedAt"]
复合查询
当简单的查询条件,不能满足查询要时,BmobQuery也提供了2种复合查询的方法。
//并查询
-(void)addTheConstraintByAndOperationWithArray:(NSArray*)array;
//或查询
-(void)addTheConstraintByOrOperationWithArray:(NSArray*)array;
数组里面存的是若干个条件字典,其格式为
@{@"列名":条件值}
例如:
//查询score列中值等于5且姓名为Mike的数据
NSArray*array= @[@{@"score":@5},@{@"name":@"Mike"}];
[bquery addTheConstraintByAndOperationWithArray:array];
支持的条件符号有
Key |
Operation |
$lt |
小于 |
$lte |
小于等于 |
$gt |
大于 |
$gte |
大于等于 |
$ne |
不等于 |
$in |
在数组中 |
$nin |
不在数组中 |
$exists |
值不为空 |
$or |
合成查询中的或查询 |
$and |
合成查询中的与查询 |
$regex |
匹配PCRE表达式 |
例如:
//查询score列中值大于150或者小于5的数据
NSArray*array= @[@{@"score":@{@"$gt":@150}},@{@"score":@{@"$lt":@5}}];
[bquery addTheConstraintByOrOperationWithArray:array];
//查询score列中值大于5和小于150的数据
NSArray*array= @[@{@"score":@{@"$gt":@5}},@{@"score":@{@"$lt":@150}}];
[bquery addTheConstraintByAndOperationWithArray:array];
需要注意的是,如果是要查找条件为等于的数据的话,直接构造成{@"列名":条件}即可,例如下面的例子:
//查找分数为90分跟分数为150分的数据
NSArray*array= @[@{@"score":@90},@{@"score":@150}];
[bquery addTheConstraintByOrOperationWithArray:array];
//查找名字为张三跟李四的数据
NSArray*array= @[@{@"name":@"张三"},@{@"name":"李四"}];
[bquery addTheConstraintByOrOperationWithArray:array];
其中日期类型和pointer类型构造的方法比较特殊。
例如要查询要个时间段的数据,可以构造时间
//createdAt大于或等于 2014-07-15 00:00:00
NSDictionary*condiction1=@{@"createdAt":@{@"$gte":@{@"__type":@"Date",@"iso":@"2014-07-15 00:00:00"}}};
//createdAt小于 2014-10-15 00:00:00
NSDictionary*condiction2=@{@"createdAt":@{@"$lt":@{@"__type":@"Date",@"iso":@"2014-10-15 00:00:00"}}};
NSArray*condictonArray=@[condiction1,condiction2];
//作用就是查询创建时间在2014年7月15日到2014年10月15日之间的数据
[bquery addTheConstraintByAndOperationWithArray:condictonArray];
如果查询的条件刚好是pointer类型的话,例如要查询某篇文章的作者是A或者B的话,可以这样构造数据:
BmobQuery*query=[BmobQuery queryWithClassName:@"Post"];
//列author为pointer类型,指向用户表
//假设用户A的objectId为aaaa ,其中classname为表名
NSDictionary*condiction1=@{@"author":@{@"__type":@"Pointer",@"className":@"_User",@"objectId":@"aaaa"}};
//假设用户b的objecId为bbbb
NSDictionary*condiction2=@{@"author":@{@"__type":@"Pointer",@"className":@"_User",@"objectId":@"bbbb"}};
NSArray*condictionArray=@[condiction1,condiction2];
//查找作者为用户A或者作者为用户B的数据
[query addTheConstraintByOrOperationWithArray:condictionArray];
[query findObjectsInBackgroundWithBlock:^(NSArray*array,NSError*error){
}];
另外我们还封装了以下方法,方便开发者使用,以下是与查询,注意add之前的查询只能添加一个条件,如果是或查询,将[main andOperation];换成[main orOperation];
BmobQuery *bquery=[BmobQuery queryWithClassName:@"GameScore_LT"];
[bquery whereKey:@"score" equalTo:[NSNumber numberWithDouble:10.3]];
BmobQuery *bquery1=[BmobQuery queryWithClassName:@"GameScore_LT"];
[bquery1 whereKey:@"playerName" equalTo:@"test"];
BmobQuery *main=[BmobQuery queryWithClassName:@"GameScore_LT"];
[main add:bquery];
[main add:bquery1];
[main andOperation];
[main findObjectsInBackgroundWithBlock:^(NSArray*array,NSError*error){
for(BmobObject*objin array){
//打印playerName
NSLog(@"%@",obj);
NSLog(@"obj.playerName = %@",[obj objectForKey:@"playerName"]);
}
}];
返回指定列
有的时候,一张表的数据列比较多,而我们只想查询返回某些列的数据时,我们可以使用以下方法来只返回需要的列的值
//设置查询后返回的字段数组
-(void)selectKeys:(NSArray*)keys;
//指定返回查询的结果包括score和playerName两列的数据
[bquery selectKeys:@[@"score",@"playerName"]];
查询结果计数
如果你只是想统计满足查询对象的数量,你并不需要获取所有匹配的对象的具体数据信息,可以直接使用count替代find。例如,查询一个特定玩家玩的游戏场数:
BmobQuery*bquery=[BmobQuery queryWithClassName:@"GameScore"];
[bquery whereKey:@"playerName" equalTo:@"Barbie"];
[bquery countObjectsInBackgroundWithBlock:^(int number,NSError *error){
NSLog(@"%d",num);
}];
统计查询
如果你想对表进行统计查询,可以采用以下方法。
统计查询方法
统计方法共有以下几种,分别用于计算总和、平均值、最大值、最小值
-(void)sumKeys:(NSArray*)keys
-(void)averageKeys:(NSArray*)keys
-(void)maxKeys:(NSArray*)keys
-(void)minKeys:(NSArray*)keys
设置完成后使用下面的方法来返回结果。
-(void)calcInBackgroundWithBlock:(BmobObjectArrayResultBlock)block
例如,如果我们要计算GameScore表所有玩家的得分总和,可以使用以下代码:
BmobQuery*bquery=[BmobQuery queryWithClassName:@"GameScore"];
NSArray*sumArray=[NSArray arrayWithObject:@"score"];
[bquery sumKeys:sumArray];
[bquery calcInBackgroundWithBlock:^(NSArray*array,NSError*error){
if(error){
NSLog(@"error is:%@",error);
}else{
if(array){
NSLog(@"%@",array);
NSDictionary *dic=[[NSDictionary alloc] init];
dic = [array objectAtIndex:0];
NSLog(@"sum of score:%d",[[dic objectForKey:@"_sumScore"] intValue] );
}
}
}];
计算总和只对Number类型的列有效,列名使用数组存放。返回的字典key值为_sum+首字母大写的列名,其它计算方法与sum类似,其返回的字典key值见下表
关键字 |
key值 |
例子 |
sum |
_sum+首字母大写 |
_sumScore |
average |
_avg+首字母大写 |
_avgScore |
max |
_max+首字母大写 |
_maxScore |
min |
_min+首字母大写 |
_minScore |
分组统计
分组可用于获取并不复杂的列值,如我想知道playerName列中有多少个不同的玩家名字,可使用以下代码:
BmobQuery*bquery=[BmobQuery queryWithClassName:@"GameScore_LT"];
NSArray*groupbyArray=[NSArray arrayWithObject:@"playerName"];
[bquery groupbyKeys:groupbyArray];
[bquery calcInBackgroundWithBlock:^(NSArray*array,NSError*error){
if(error){
NSLog(@"error is:%@",error);
}else{
if(array){
NSLog(@"%@",array);
for (NSDictionary*dicin array){
NSString *playerName=[dic objectForKey:@"playerName"];
NSLog(@"player:%@",playerName);
}
}
}
}];
另外,groupby可以结合计算函数来使用,比如我想统计每个玩家的总分,可以使用以下代码:
BmobQuery*bquery=[BmobQuery queryWithClassName:@"GameScore"];
NSArray*groupbyArray=[NSArray arrayWithObject:@"playerName"];
NSArray*sumArray=[NSArray arrayWithObject:@"score"];
[bquery groupbyKeys:groupbyArray];
[bquery sumKeys:sumArray];
[bquery calcInBackgroundWithBlock:^(NSArray*array,NSError*error){
if(error){
NSLog(@"error is:%@",error);
}else{
if(array){
NSLog(@"%@",array);
for (NSDictionary*dicin array){
NSString *playerName=[dic objectForKey:@"playerName"];
NSString *sum=[dic objectForKey:@"_sumScore"];
NSLog(@"player:%@\tsum:%@",playerName,sum);
}
}
}
}];
分组记录数
有时候,我们还想知道分组统计时每个分组有多少条记录,设置isGroupcount为YES即可,如下:
bquery.isGroupcount= YES;
这样在返回的结果中就会包含类似于以下的键值对:
_count =10
添加过滤条件
利用计算方法返回来的值可以通过限制条件来获取我们想关注的结果。添加条件使用以下方法。
-(void)constructHavingDic:(NSDictionary*)havingDic
该方法通过构造havingDic来添加限制条件,其使用方法与复杂查询类似。
例如,我们统计每个玩家的总分,但我们只需要得到总分大于50的玩家,可以使用以下代码得到:
BmobQuery*bquery=[BmobQuery queryWithClassName:@"GameScore"];
NSArray*groupbyArray=[NSArray arrayWithObject:@"playerName"];
[bquery groupbyKeys:groupbyArray];
NSArray*sumArray=[NSArray arrayWithObject:@"score"];
[bquery sumKeys:sumArray];
NSDictionary*condication=[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:50],@"$gt",nil];
[bquery constructHavingDic:[[NSDictionary alloc] initWithObjectsAndKeys:condication,@"_sumScore",nil]];
[bquery calcInBackgroundWithBlock:^(NSArray*array,NSError*error){
if(error){
NSLog(@"error is:%@",error);
}else{
if(array){
NSLog(@"%@",array);
for (NSDictionary*dicin array){
NSString *playerName=[dic objectForKey:@"playerName"];
NSString *sum=[dic objectForKey:@"_sumScore"];
NSLog(@"player:%@\tsum:%@",playerName,sum);
}
}
}
}];
缓存查询
缓存查询通常是将查询结果缓存在磁盘上,当用户的设备处于离线状态时,就可以从缓存中获取数据来显示。或者在应用界面刚刚启动,从网络获取数据还未得到结果时,先使用缓存数据来显示。这样可以让用户不必在按下某个按钮后进行枯燥的等待。 默认的查询操作是没有启用缓存的,开发者可以通过设置BmobCachePolicy来启用缓存功能。例如:优先从网络获取数据,如果获取失败时再从缓存获取数据,这种情况通常用在网络不可用的情况下。
bquery.cachePolicy= kBmobCachePolicyNetworkElseCache;
[bquery findObjectsInBackgroundWithBlock:^(NSArray*array,NSError*error){
}];
BmobSDK提供几种不同的缓存策略,以使用不同应用场景的需求。
只从网络获取数据,且数据不会缓存在本地,这是默认的缓存策略。
只从缓存读数据,如果缓存没有数据,返回一个空数组。
只从网络获取数据,同时会在本地缓存数据。
先从缓存读取数据,如果没有再从网络获取。
先从网络获取数据,如果没有,再从缓存读取。
先从缓存读取数据,无论结果如何都会再次从网络获取数据,在这种情况下,Block将产生两次调用。通常这种做法是先快速从缓存读取数据显示在界面,然后在后台连接网络获取最新数据,取到后再更新界面。
|检查是否存在当前查询条件的缓存数据
[bquery hasCachedResult];
存在返回YES,否则返回NO
|清除当前查询的缓存数据
[bquery clearCachedResult];
|清除所有查询结果的缓存数据
[BmobQuery clearAllCachedResults];
|设置缓存有限时间,单位为秒
bquery.maxCacheAge=10000;
BQL查询
Bmob Query Language(简称 BQL)是 Bmob 自BmobSDK V1.5.7 版本开始,为查询 API 定制的一套类似 SQL 查询语法的子集和变种,主要目的是降低大家学习 Bmob 查询 API 的成本,可以使用传统的 SQL 语法来查询 Bmob 应用内的数据。
具体的 BQL 语法,请参考 Bmob Query Language 详细指南。
基本BQL查询
可以通过以下方法来进行SQL查询:
例如:需要查询所有的游戏得分记录
BmobQuery*bmobQuery=[[BmobQuery alloc] init];
NSString*bql=@"select * from GameScore_BQL";
[bmobQuery queryInBackgroundWithBQL:bql block:^(BQLQueryResult*result,NSError*error){
if(error){
NSLog(@"%@",error);
}else{
if(result){
NSLog(@"%@",result.resultsAry);
}
}
}];
其中result.resultsAry为BmobObject数组。
如果需要查询个数,则可以这样:
NSString*bql=@"select count(*) from GameScore_BQL";
BmobQuery*bmobQuery=[[BmobQuery alloc] init];
[bmobQuery queryInBackgroundWithBQL:bql block:^(BQLQueryResult*result,NSError*error){
if(error){
NSLog(@"%@",error);
}else{
if(result){
NSLog(@"%d",result.count);
}
}
}];
其中result.count为记录条数,需要注意的是如果没有使用count关键字进行查询的话,对象result的count属性是没有意义的。
统计BQL查询
由于统计查询的结果是不定的,故BQL提供了另外一种查询方法来进行统计查询,可以使用- (void)statisticsInBackgroundWithBQL:(NSString *)bql block:(BmobBQLArrayResultBlock)block; 方法来进行。
NSString*bql=@"select sum(score) from GameScore_BQL group by playerName";
[bmobQuery statisticsInBackgroundWithBQL:bql block:^(NSArray*result,NSError*error){
if(error){
NSLog(@"%@",error);
}else{
if(result){
NSLog(@"%@",result);
}
}
}];
目前统计查询支持的关键字如下表所示,即如果在sql语句中包含以下关键字时,则需要使用统计查询方法才能返回正确结果:
key |
Operation |
group by |
分组操作 |
groupcount |
返回每个分组的总记录 |
having |
分组中的过滤条件 |
sum |
计算总和 |
average |
计算平均值 |
max |
计算最大值 |
min |
计算最小值 |
占位符查询
在更多的时候,一个查询语句中间会有很多的值是可变值,为此,我们也提供了类似 Java JDBC 里的PreparedStatement 使用占位符查询的语法结构。
注:目前只有where和limit关键字以及内置函数支持使用占位符。
普通查询
BmobQuery*bmobQuery=[[BmobQuery alloc] init];
NSString*bql=@"select * from GameScore_BQL where playerName = ? and score = ?";
NSArray*placeholderArray=@[@"name2",@9];
[bmobQuery queryInBackgroundWithBQL:bql pvalues:placeholderArray block:^(BQLQueryResult*result,NSError*error){
if(error){
NSLog(@"%@",error);
}else{
if(result){
NSLog(@"%@",result.resultsAry);
}
}
}];
数组中的数据会依次替换bql中的问号。
内置函数
对于包含内置函数的占位符查询,比较特殊,请使用Bmob Query Language 详细指南中的内置函数中占位符查询用到的内置函数用到的内置函数列出的形式进行查询操作:
举例:我想查询在 '2015-05-14 14:56:30' 后的创建的记录,可以这样:
BmobQuery*bmobQuery=[[BmobQuery alloc] init];
NSString*bql=@"select * from GameScore_BQL where createdAt > date(?)";
NSArray*placeholderArray=@[@"2015-05-14 14:56:30"];
[bmobQuery queryInBackgroundWithBQL:bql pvalues:placeholderArray block:^(BQLQueryResult*result,NSError*error){
if(error){
NSLog(@"%@",error);
}else{
if(result){
NSLog(@"%@",result.resultsAry);
}
}
}];
注
1、我们更推荐使用占位符语法,理论上会降低 BQL 转换的性能开销;
2、同样的,统计查询也支持占位符,只需要- (void)statisticsInBackgroundWithBQL:(NSString *)bql pvalues:(NSArray*)pvalues block:(BmobBQLArrayResultBlock)block;方法即可。
BQL缓存策略
如果要使用缓存策略,可用 - (void)queryBQLCanCacheInBackgroundWithblock:(BmobBQLObjectResultBlock)block; 方法,样例代码如下:
NSString*bql=[NSString stringWithFormat:@"select * from %@ where %@ = ?",TABLENAME,COLPLAYERNAME];
NSArray*placeholder=@[@"name1"];
BmobQuery*bmobQueryWriteCache=[[BmobQuery alloc] init];
bmobQueryWriteCache.cachePolicy= kBmobCachePolicyNetworkOnly;
[bmobQueryWriteCache setBQL:bql];
[bmobQueryWriteCache setPlaceholder:placeholder];
[bmobQueryWriteCache queryBQLCanCacheInBackgroundWithblock:^(BQLQueryResult*result,NSError*error){
if(error){
NSLog(@"%@",error);
}elseif(result){
NSLog(@"actual:%@",result);
}
}];
注意:
缓存策略只对普通查询有效,统计查询只支持从网络进行查询。具体使用可参考iOS开发文档中的查询缓存查询小节。
http://docs.bmob.cn/data/iOS/b_developdoc/doc/index.html#查询