SharePoint Online : Working with People Search and User Profiles


Introduction

People Search and User Profiles are amongst the popular topics that everyone uses in their projects every now and then. With SharePoint 2013, a lot of functionality has been included in the Client API's by Microsoft. If you consider user profiles itself, in SharePoint 2010 you cannot fetch user profiles using client-side object model. However, with SharePoint 2013, you have a wide variety of methods that you can use to fetch the user profile information using the client object model. The search API is also expanded greatly.

Content Search WebPart is one of the important additions in SharePoint 2013. Using this webpart you can display content that was crawled and added to the search index.

Scenario

The scope of this article is to talk about how we can make use of search and user profile API so that based upon the search query we can fetch all users using the people search API and then retrieve their profile information using user profile API. All this will be implemented purely using the client object model. 

It's important to mention here that using user profile client API, we cannot retrieve all user profiles. For such a scenario, the recommended approach first makes use of people search API to fetch user profiles and once you have all users, simply make use of user profile API to fetch the profile information.

Approach

In addition to server-side object model available in previous versions, Search and User Profiles in SharePoint 2013 provides the following set of API's.

  1. .NET Client Object Model

  2. REST Service

  3. JavaScript Client Object Model

Prerequisites

For search, you need to have the following prerequisites based upon the approach you are using.

  1. Microsoft.SharePoint.Client.Search.dll - If you are making use of .NET client object model you need to add a reference to this dll.

  2. SP.Search.js - If you are using JSOM, you need to ensure that this js file is loaded on the page.

  3. http://<siteUri>/_api/search/- If you are making a REST call then you need to use this access point.

For user profiles, you need to have the following prerequisites based upon the approach you are using.

  1. Microsoft.SharePoint.Client.UserProfiles.dll **- **If you are making use of .NET client object model you need to add reference to this dll.

  2. **SP.UserProfiles.js **- If you are using JSOM, you need to ensure that this js file is loaded on the page.

  3. **http://<siteUri>/_api/SP.UserProfiles.PeopleManager **- If you are making a REST call then you need to use this access point.

Implementation

Let us jump into the actual implementation so that there is more clarity.

Fetch All Users

As we discussed above, using people search we can fetch all the users.

Performing People Search using REST API

Let us discuss what we did above.

Constructed the URI and made a GET request to the Search REST service using the api "/_api/search/query"

Next thing was to specify the query parameters in the URL.  The syntax for the same is like below.

http://server/_api/search/query?query_parameter=value&query_parameter=value

If we look at the URL in the screenshot above there are two parameters that we are using “querytext” and “sourceid”.

Querytext: This parameter holds the text that we are using for search query.

SourceId: This parameter holds the result source id that we want to use for executing the search query. In the above screen, if you have a look, we are making use of “B09A7990-05EA-4AF9-81EF-EDFAB16C4E31” as the sourceid. This is the id of “Local People Results” result source. Have a look at this link to see list of common result source id’s.

The response retrieved in the browser is in the form of an XML shown in the screenshot above. Let us discuss some interesting properties in this XML.

The RowCount property in the above snippet signifies the count of search results returned based upon our query. In our case, a count of 2 signifies two records returned by the search.

The QueryModification property in the above snippet signifies the query that we are using. As you can see in the value attribute we are having “geet*” which was our Querytext parameter value and then we have “ContentClass=urn:content-class:SPSPeople” which is the result source for “Local People Results” i.e. the guid that we passed in the URL.

The above snippet shows a table having two rows. These two rows are the two records returned by our search query. Expanding each row will show the profile information of the respective user.

In the above snippet, we can see different managed properties for the user like “AboutMe”, “AccountName” etc.

Performing People Search using JSOM

After having a look at how we can fetch the users using people search, let us discuss how we can make use of the JavaScript Client Object Model to achieve the same.

//Method to fetch all the users
    function getAllUsers() {
 
        //Textbox value containing search term
        var searchTerm = $("#txtSearchBox").val();
 
        clientContext = new  SP.ClientContext.get_current();
         
        //Building Keyword query for the search
        var keywordQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(clientContext);
        keywordQuery.set_queryText(searchTerm);
        keywordQuery.set_sourceId("B09A7990-05EA-4AF9-81EF-EDFAB16C4E31");
        keywordQuery.set_rowLimit(500);
        keywordQuery.set_trimDuplicates(false);
 
        var searchExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(clientContext);
        results = searchExecutor.executeQuery(keywordQuery);
         
        clientContext.executeQueryAsync(onQuerySuccess, onQueryError);
 
 
    }

In the above code snippet, we are first fetching the query text from the search textbox. Then we make use of KeywordQuery class. 

keywordQuery.set_queryText(“your query text”) : Sets the query text for the search query.

keywordQuery.set_sourceId(“result source id”): Sets the identifier (ID) of the result source to be used to run the query.

keywordQuery.set_rowLimit(“limit”): Sets the maximum number of rows returned in the search results.

keywordQuery.set_trimDuplicates(“boolean”): Sets a Boolean value that specifies whether the search query should run if the query text contains only noise words.

Once all the above filter parameters are set then we just need to create a SearchExecutor object and execute the query.

After that, you simply need to make an async call to the server to fetch the search results.

  function onQuerySuccess() {
 
       $.each(results.m_value.ResultTables[0].ResultRows, function  () {
            users.push(this.AccountName);
 
        });
 
        fetchProfilePropertiesForUsers();
 
    }

If you have a look at the above code snippet, you will observe that the search query will return the number of results returned simply by examining results.m_value. Each individual result can be obtained results.m_value.ResultTables[0].ResultRows. You can directly access the managed properties of each row using the name of the property on the object like this.AccountName. In the code snippet, we are simply iterating through each row returned and fetching the AccountName for every result row. We are saving these account names in an array here i.e. users array. We will talk about how we are using this users array and the fetchProfileProperiesForUsers method in a while.

So, this is how we can fetch all the profiles based on a search using the JavaScript Client Object Model.

Similarly, you can perform the search using the .NET client-side object model as well.

Fetch Profile Information

Now that we have all the users available based on the search query, let us try to fetch the user profile information.  In the scope of this article, we will make use of the JavaScript Client Object Model to achieve this requirement.

If you remember, when we got our search results, we stored usernames in users array and we made a call to fetchProfilePropertiesForUsers method over there. The below code snippet shows the actual implementation of this method.

  function fetchProfilePropertiesForUsers() {
 
        var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
 
        var profilePropertyNames = ["PreferredName", "PictureURL",  "AboutMe", "TechNetProfile", "AccountName"];
 
        for (var i = 0; i < users.length; i++) {
            var userProfilePropertiesForUser = new SP.UserProfiles.UserProfilePropertiesForUser(clientContext, users[i], profilePropertyNames);
            userProfileProperties[i] = peopleManager.getUserProfilePropertiesFor(userProfilePropertiesForUser);
        }
 
        clientContext.executeQueryAsync(onSuccess, onQueryError);
    }

First, we make an instance of the PeopleManager class. This class is very important and forms the power engine of the user profile. Once we have instantiated this we need to specify which properties we are interested in fetching for the users. In our case, we have specified the “PreferredName”, “PictureURL”, “AboutMe”, “TechNetProfile” and the “AccountName” as the properties of our interest. The next step is to iterate through each user and fetch the property values for all the above-mentioned properties. We first create an instance of UserProfilePropertiesForUser. The constructor accepts the client context, the account name and the string[] containing the properties that we want to fetch for the given user. After that, we create an array object containing the user profile properties. Now simply iterate through this object to fetch user profile property values for every individual profile.

function onSuccess() {
         
        var html = "<style type='text/css'> .floatL {float:left;margin:10px;} .floatR {padding-top:10px} .profile {padding:10px 10px;} .editProfile{margin-left:100px;}  div>img {height:72px;width:72px;} </style>";
        for (var i = 0; i < userProfileProperties.length; i++) {
 
           html += "<div class='profile'><div class='floatL'><img src='" + userProfileProperties[i][1] + "' href='#' /></div><div class='floatR'><h2><span>" + userProfileProperties[i][0] + "</span></h2><span>About Me : " + userProfileProperties[i][2] + "</span><br /><span>TechNet Profile : </span><a href='" + userProfileProperties[i][3] + "'>" + userProfileProperties[i][3] + "</a><br /></div></div><br />";
            
 
        }
 
        $("#divUserProfiles").html(html);
 
    }

The complete code is as follows. Create a page in your SharePoint Online site and add the following code in a script editor webpart on the page.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="/_layouts/15/sp.runtime.js" type="text/javascript"></script>
<script src="/_layouts/15/sp.js" type="text/javascript"></script>
<script src="/_layouts/15/sp.search.js" type="text/javascript"></script>
<script src="/_layouts/15/sp.UserProfiles.js" type="text/javascript"></script>
 
<script type="text/javascript">
    $(document).ready(function () {
 
        $("#btnSearch").click(function () {
            users = [];
            userProfileProperties = [];
            SP.SOD.executeFunc('sp.js', 'SP.ClientContext', getAllUsers);
 
        });
 
 
    });
 
    var users = [];
    var userProfileProperties = [];
 
    //Method to fetch all the users
    function getAllUsers() {
 
        //Textbox value containing search term
        var searchTerm = $("#txtSearchBox").val();
 
        clientContext = new SP.ClientContext.get_current();
         
        //Building Keyword query for the search
        var keywordQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(clientContext);
        keywordQuery.set_queryText(searchTerm);
        keywordQuery.set_sourceId("B09A7990-05EA-4AF9-81EF-EDFAB16C4E31");
        keywordQuery.set_rowLimit(500);
        keywordQuery.set_trimDuplicates(false);
 
        var searchExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(clientContext);
        results = searchExecutor.executeQuery(keywordQuery);
         
        clientContext.executeQueryAsync(onQuerySuccess, onQueryError);
 
 
    }
    function onQueryError(sender, args) {
        alert(args.get_message());
    }
    function onQuerySuccess() {
 
       $.each(results.m_value.ResultTables[0].ResultRows, function () {
            users.push(this.AccountName);
 
        });
 
        fetchProfilePropertiesForUsers();
 
    }
 
    
    function fetchProfilePropertiesForUsers() {
 
        var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
 
        var profilePropertyNames = ["PreferredName", "PictureURL", "AboutMe", "TechNetProfile", "AccountName"];
 
        for (var i = 0; i < users.length; i++) {
            var userProfilePropertiesForUser  = new SP.UserProfiles.UserProfilePropertiesForUser(clientContext, users[i], profilePropertyNames);
            userProfileProperties[i] = peopleManager.getUserProfilePropertiesFor(userProfilePropertiesForUser);
        }
 
        clientContext.executeQueryAsync(onSuccess, onQueryError);
    }
 
    function onSuccess() {
         
        var html = "<style type='text/css'> .floatL {float:left;margin:10px;} .floatR {padding-top:10px} .profile {padding:10px 10px;} .editProfile{margin-left:100px;}  div>img {height:72px;width:72px;} </style>";
        for (var i = 0; i < userProfileProperties.length; i++) {
 
           html += "<div class='profile'><div class='floatL'><img src='" + userProfileProperties[i][1] + "' href='#' /></div><div class='floatR'><h2><span>" + userProfileProperties[i][0] + "</span></h2><span>About Me : " + userProfileProperties[i][2] + "</span><br /><span>TechNet Profile : </span><a href='" + userProfileProperties[i][3] + "'>" + userProfileProperties[i][3] + "</a><br /></div></div><br />";
            
 
        }
 
        $("#divUserProfiles").html(html);
 
    }
 
     
 
 
</script>
 
 
<input type="text" id="txtSearchBox" /> <input id="btnSearch" type="button" value="Search Users" />
 
<div id="divUserProfiles"></div>

The end result will look like below.

Conclusion

Hope this article gives enough insights to help you understand how we can work with people search as well as user profile service in SharePoint.


References

  1. SharePoint 2013 Search REST API
  2. Search in SharePoint 2013
  3. Search Query API
  4. Result Sources for Search
  5. KeywordQuery Class
  6. Query Search with CSOM
  7. SearchExecutor class
  8. JSOM and Search Query
  9. Microsoft.SharePoint.Client.UserProfiles
  10. PeopleManager class
  11. UserProfilePropertiesForUser class
  12. SP.UserProfiles.js
  13. SP.UserProfiles.PeopleManager
  14. SP.UserProfiles.UserProfilePropertiesForUser
  15. SP.UserProfiles.PeopleManager.getUserProfilePropertiesFor

 
You can download the complete source code from TechNet gallery link here.

See Also