salesforce零基础学习(七十五)浅谈SOSL(Salesforce Object Search Language)

在工作中,我们更多操作的是一个表的对象,所以我们对SOQL的使用很多。但是有时候,我们需要对几个表进行查询操作,类似salesforce的全局搜索功能,这时,使用SOQL没法满足功能了,我们就需要使用SOSL.其实不只是多个表检索可以使用SOSL,如果针对某个字段进行高级的检索也可以使用SOSL。

背景:Account表中的Name字段,存储了以下的数据

1.上海电信

2.上海-电信

3.上海(电信)

4.电信-上海

5.电信上海

6.电信(上海)

7.上海xx电信

8.海上信电

9.海信电上。

当用户搜索上海电信时,需要将1,2,3,4,5,6,7检索出来,8,9排除。使用正常的SOQL语句实现起来难度较大,这种情况可以考虑使用SOSL,尽管SOSL不一定将所有的结果返回,但是可以返回大部分情况。

一.SOSL简单介绍

SOSL全称为Salesforce Object Search Language。SOSL查询可以在以下环境使用:

Search()的调用/apex语句/Visualforce的Controller和getter方法里面/Eclipse的Schema Explorer(没有测试成功)

SOSL支持对多个objects同时查询text/email/phone类型字段的数据,SOSL可以查询标准的对象以及自定义的对象。当然SOSL不是所有的对象或者字段都支持搜索,以下情况下是不允许搜索的:

1.sObject不允许搜索:创建sObject或者自带标准sObject,只有允许搜索的sObject才可以使用SOSL,判断一个sObject是否可以搜索,可以使用Schema的DescribeSObjectResult类来判断,如果希望一个自定义对象允许搜索,只需要把allow search勾选即可。

2.Number, date, or checkbox 这几种类型是不支持使用SOSL的,如果需要搜索这几种,需要使用SOQL。

3.Textarea 类型,除非SearchGroup选择的是ALL FIELDS,否则不支持搜索。

4.关联到对象上的Attachment数据不允许搜索。

除了上述的使用限制以外,其实SOSL还有一些其他的限制,比如SOSL语句长度不能超过20000个字符,超过的话会报error。其他的限制详看开发文档。

SOSL在apex中调用时,search query使用的是单引号'',在search调用中使用的是{},下面的demo以及代码均以apex写法为主。

二.SOSL的语法

SOSL的语法如下:

1.FIND:搜索指定的文本,如果searchQuery超过10000,则无结果返回,如果超过4000,所有的逻辑都将移除。SearchQuery除了纯文本以外,还可以使用*或者?的通配符进行匹配,*代表后面的所有位为任意内容,?代表后面的一位为任意内容。

比如FIND 'z*o'会将所有zero,zoo数据查询出来,但是'z?o'会过滤掉zero对应的数据,只会查出zoo对应的数据。

searchQuery也可以使用与或等操作,详情查看SOQL与SOSL开发文档。

2.IN:设置查询组--即查询的类型,SearchGroup包含四种固定的类型:ALL FIELDS/EMAIL FIELDS/NAME FIELDS/PHONE FIELDS。如果想要在Name或者Email/Phone类型中进行搜索,则可以设置指定的类型,否则设置ALL FIELDS,默认查询组为ALL FIELDS。

3.RETURNING:此部分作为搜索返回结果的处理部分,显得尤为重要,RETURNING可以返回一个对象,也可以返回多个对象,多个对象通过逗号分隔;对象中可以返回多个字段,也可以在返回的结果中添加自定义的逻辑。比如我们希望搜索Opportunity和Account的Name中包含zero中的数据,其中,要求Opportunity中的数据按照创建日期正序排列,只查询十条,并且只搜索Name和StageName字段,Account要求Name除了含有zero以外还需要包含zhang,并且最多只查询1条,这种情况下RETURNING就可以发挥神奇的作用了。

eg:FIND 'zero' IN ALL FIELDS RETURNING account(where Name like '%zhang%' limit 1),Opportunity(Name,StageName order by createddate asc limit 10)

备注(如果使用order by,object的field不能为空,如果上述内容修改成以下写法便是错误的)

FIND 'zero' IN ALL FIELDS RETURNING account(where Name like '%zhang%' limit 1),Opportunity(order by createddate asc limit 10)

其他部分自行查看开发文档。

三.SOSL应用

封装了一个SOSL工具类,用户可以根据需要查询的关键字,设置返回的结果的格式来返回需要的数据,如果不设置returning的field的内容,则默认返回所有可以访问的字段,否则返回指定字段:

代码语言:javascript复制 1 public with sharing class SOSLController {

2

3 public class RetrieveWrapper {

4 //keyword:used to retrieve this

5 public String retrieveKeyword{get;set;}

6 //search group: values :(ALL FIELDS/EMAIL FIELDS/NAME FIELDS/PHONE FIELDS/SIDEBAR FIELDS)

7 public String searchGroup{get;set;}

8 //obj api name -> field eg: account->[Name,Site]

9 public Map> objName2FieldsMap{get;set;}

10 //obj api name -> condition eg : account -> where name like 'test%' order by name asc limit 10 offset 1

11 public Map objName2QueryConditionMap{get;set;}

12 }

13

14 public class SearchResultWrapper {

15 //sobject api name eg:Account

16 public String objName{get;set;}

17 //sObject Field Name => Value

18 public Map objFieldName2Value{get;set;}

19 }

20

21 public static List search(RetrieveWrapper wrapper) {

22 String retrieveSQL = buildRetrieveSQL(wrapper);

23 List searchResultWrappers = new List();

24 if(retrieveSQL == null || (!retrieveSQL.contains('FIND'))) {

25 return null;

26 }

27 System.debug(LoggingLevel.INFO, '*** retrieveSQL: ' + retrieveSQL);

28 List> searchResults = search.query(retrieveSQL);

29 if(searchResults.size() > 0) {

30 for(List objs : searchResults) {

31 String objName;

32 if(objs.size() > 0) {

33 String objId = objs.get(0).Id;

34 objName = getAPINameByObjId(objId);

35 }

36 List retrieveFields;

37 if(objName != null) {

38

39 if(wrapper.objName2FieldsMap != null && wrapper.objName2FieldsMap.get(objName) != null) {

40 retrieveFields = wrapper.objName2FieldsMap.get(objName);

41 } else {

42 retrieveFields = getAvailableFields(objName);

43 }

44 }

45

46 for(sObject obj : objs) {

47 SearchResultWrapper resultWrapper = new SearchResultWrapper();

48 resultWrapper.objName = objName;

49 Map fieldValueMap = new Map();

50 for(String field : retrieveFields){

51 if(obj.get(field) != null) {

52 fieldValueMap.put(field, obj.get(field));

53 }

54 }

55 resultWrapper.objFieldName2Value = fieldValueMap;

56 searchResultWrappers.add(resultWrapper);

57 }

58 }

59 }

60 return searchResultWrappers;

61 }

62

63 private static String buildRetrieveSQL(RetrieveWrapper wrapper) {

64 String fetchSQL;

65 if(wrapper.retrieveKeyword != null && wrapper.retrieveKeyword.trim() != '') {

66 String keyword = '\'' + wrapper.retrieveKeyword + '\'';

67 fetchSQL = 'FIND ' + keyword;

68

69 if(wrapper.searchGroup != null) {

70 fetchSQL += ' IN ' + wrapper.searchGroup;

71 } else {

72 fetchSQL += ' IN ALL FIELDS';

73 }

74

75 if(wrapper.objName2FieldsMap != null) {

76 List objToFieldsList = new List();

77 for(String key : wrapper.objName2FieldsMap.keySet()) {

78 String objName = key;

79 String fieldStr;

80 if(wrapper.objName2FieldsMap != null && wrapper.objName2FieldsMap.get(objName) != null) {

81 fieldStr = String.join(wrapper.objName2FieldsMap.get(objName),',');

82 } else {

83 fieldStr = String.join(getAvailableFields(objName), ',');

84 }

85 String filterStr;

86 if(wrapper.objName2QueryConditionMap != null) {

87 filterStr = wrapper.objName2QueryConditionMap.get(objName);

88 }

89

90 if(String.isNotEmpty(filterStr)){

91 fieldStr = '(' + fieldStr + ' WHERE ' + filterStr +')';

92 }

93 else{

94 if(fieldStr != null) {

95 fieldStr = '(' + fieldStr +')';

96 }

97 }

98 if(fieldStr != null) {

99 objName = key + fieldStr;

100 } else {

101 objName = key;

102 }

103

104 objToFieldsList.add(objName);

105 }

106

107 if(objToFieldsList.size() > 0) {

108 fetchSQL += ' RETURNING ' + String.join(objToFieldsList, ',');

109 }

110 }

111 }

112 return fetchSQL;

113 }

114

115 private static String getAPINameByObjId(String objId) {

116 String objPrefix = objId.left(3);

117 return objId2APIName.get(objPrefix);

118 }

119

120

121 private static Map objId2APIName {

122 get {

123 if(objId2APIName == null) {

124 objId2APIName = new Map();

125 Map gd = Schema.getGlobalDescribe();

126 for(String objectName : gd.keySet()) {

127 Schema.SObjectType objectType = gd.get(objectName);

128 String prefix = objectType.getDescribe().getKeyPrefix();

129 if(prefix != null) {

130 objId2APIName.put(prefix, objectName);

131 }

132 }

133 }

134 return objId2APIName;

135 }

136 set;

137 }

138

139 private static List getAvailableFields(String objName) {

140 List availableFields = new List();

141 List objDescribes = Schema.describeSObjects(new List{objName});

142 Schema.DescribeSObjectResult objDescribe;

143 if(objDescribes != null && objDescribes.size() > 0) {

144 objDescribe = objDescribes.get(0);

145 } else {

146 return null;

147 }

148 Map sObjectFieldMaps = objDescribe.fields.getMap();

149 for(String objField : sObjectFieldMaps.keySet()) {

150 SObjectField field = sObjectFieldMaps.get(objField);

151 DescribeFieldResult fieldResult = field.getDescribe();

152 if(fieldResult.isAccessible()) {

153 availableFields.add(fieldResult.getName());

154 }

155 }

156 return availableFields;

157 }

158 }调用代码如下:

代码语言:javascript复制SOSLController.RetrieveWrapper wrapper = new SOSLController.RetrieveWrapper();

wrapper.retrieveKeyword = '上海电信';

wrapper.objName2FieldsMap = new Map>();

List userFieldsList = new List();

userFieldsList.add('Name');

wrapper.objName2FieldsMap.put('account',userFieldsList);

//wrapper.objName2FieldsMap.put('account',null);

List searchResults = SOSLController.search(wrapper);

System.debug(LoggingLevel.INFO, '*** searchResults: \n' + JSON.serializePretty(searchResults));结果:

总结:本篇只是描述一下SOSL的基本使用,还有很多细节使用以及限制没有涉及。本篇只起到抛砖引玉效果,如果项目中需要使用SOSL或者想要研究的,最好先自行查看文档。

世界杯2026香港直播︱Now TV免费直播14场热身赛 ViuTV免费直播25场精选赛事时间表
化石翼龙性格配招(化石翼龙性格配招3dm)
Copyright © 2022 全球游戏最新活动中心 All Rights Reserved.