Tuesday, May 17, 2011

Most viewed documents in SharePoint 2010

The Task

You want to see the top 10 most viewed documents in a library

The Answer

1. Enable the two reporting features in your site collection features.
Enable the reporting features


2. Go to the list and click on "Library Settings" in the ribbon

Library Settings


3. Click on "Information management policy settings" under "Permission and Management"
Information management policy settings


4. Click on document

5. Activate the checkbox "Enable Auditing" and select "Opening or downloading documents, viewing items in lists, or viewing item properties"
Enable Auditing


Now the auditing is enabled and each time when an item in the doclib is viewed a log entrie is generated. You can limit the size of the lib in the site collection settings under "Site collection audit settings" in the group "Site Collection Administration". Here you can specify that the log should be holded for a period of time.


6. Create a custom webpart or control. Here is the sample code to get the entries you want

 using (SPSite site = new SPSite(mUrl))  
 {  
   using (SPWeb web = site.OpenWeb())  
   {  
     SPList list = web.Lists[mListName];  
     SPAuditQuery spQuery = new SPAuditQuery(site);  
     spQuery.RestrictToList(list);  
     SPAuditEntryCollection auditCol = site.Audit.GetEntries(spQuery);      
     // Getting Audits  
     foreach (SPAuditEntry entry in auditCol)  
     {  
       if (entry.ItemType == SPAuditItemType.Document && entry.Event == SPAuditEventType.View)  
       {                
         // Some Code to cumulate results or linq perhaps  
         // by entry.ItemIds in to an other list or array  
       }  
     }  
     // Show top ten  
     SPListItem item = null;  
     foreach (Guid guid in topTenList) {  
       item = list.GetItemByUniqueId(guid);  
       Console.WriteLine("Item: {0}", item.Name);  
     }  
   }  
 }  

You have to cumulate the results and display the top ten. This is at the same time the disadvantage of this solution. If you have large lists, the accumulation can be time consuming. A solution for that can be a timer job which writes the nr into hidden field in the library or an object cache.

Additional info

SharePoint offers a webanalytics webpart out of the box. It is within the "Content Rollup" webparts group. To use the webanalytics webparts, the webanalytics service must be started. The webanalytics webparts uses a webanalytics service proxy to get the data. Unfortunately the proxy class is internal. I couldn't found any API to access the webanalytics data, perhaps Microsoft will provide it later. The reporting db offers some stored procedures, but they were too complicated for me.

11 comments:

SharePoint Migration said...

Very good post. Thanks for these updates.

Stina Nilsson said...

Hi, Thanks for a great post. I have a qustion you might have the answer to. Is there any way to programmatically capture if current user has opened an item?

The thing i want to do is that i want to get a list of non-open items in a specific list for logged in user.

Any kind of help would be appreciated.

Thx

Stina

Merope said...

Good tip, thanks!
Is there a way to apply this to pages rather than documents?

Baris Bikmaz said...

A Page is also a document in SharePoint. Therefore you have to enabled auditing on the pages library. If you mean Web of Sites than you have to activate auditing on site collection level and check for SPAuditItemType.Web.

For pages the most easiest way would be to check the two SPAuditEntry Properties DocLocation and LocationType. LocationType should be = SPAuditLocationType.URL. Then check the DoLocation property if it contains the string "/pages/".

Baris Bikmaz said...

@Stina Nilsson: You can capture all documents viewed by a user. The auting saves the UserID for each event. (The ID of a User within a sitecollection). You have also the ItemID in the logs.

That means you loop through the SPList and save them in an hash with the Guid as key. Than you loop through the audit log and remove all entries from the hash, which the current user has already viewed. (The way is of cource not performant)

YashSub said...

Hi,
Thanks for the post.

Can we create same without using Auditing?

Baris Bikmaz said...

I've never tried, but could you add the Webanalytics Webpart to your page , activate the feeds of the webpart and use it as source for your webpart or JavaScript.

Another idea would be perhaps to write your own HTTP Handler and manage the count of views in your own database table.

vikranthreddy said...

thanks for the information.i have one question here is there any way to get the top viewed documents from more than one list(in my case i want to get from 6 lists).
Thanks in advance.

Regards,
Vikranth CH.

Baris Bikmaz said...

@vikranthreddy: Never tried it before but you can remove the restriction spQuery.RestrictToList(list), create an array of Lists you want to include. Check if entry.Doclocation within this list.

string[] lists = { "sites/MySiteCollection/MySubsite/Documents1", "sites/MySiteCollection/MySubsite/Documents2" };
entry.LocationType == SPAuditLocationType.Url && lists.Contains(entry.DocLocation)

jeremy said...

Thanks for your post! Do you know if this will work for Anonymous users too? Would it just give us blank user information?

Baris Bikmaz said...

Hard to say, never tried. But I think it can work as you said with blank user information.