Searching for Files with CAML

I was interested in searching for a file in a Document Library. Using a CAML query is much more efficient than iterating through the Document Library and examining each file. There are a couple of scenarios.

Searching at the root level of the Document Library

Searching for files is a little different from searching for other list items. In SharePoint, a file is shown with the same attributes as any other list item. When creating the CAML query, it would seem natural to search a field such as Title for a given file name. However, for a document, the Title field by default doesn’t store the file name. Rather, it contains arbitrary content that can be edited in Word (under the document’s Properties).

Furthermore, when creating the CAML query, you must reference a field using its internal name. So you won’t be able to use a field such as “Name”, as it is not a valid internal name (source: List of internal names for SharePoint fields).

Incorrect internal name error
If you don’t use the correct internal name of a field in a query, you may get the following error when attempting to access the results of the query: One or more field types are not installed properly. Go to the list settings page to delete these fields.

The correct field to use when searching for files is FileLeafRef, which is the appropriate internal name to use for the Name field. The C# snippet to create the query is as follows:

SPQuery query = new SPQuery();
query.Query = @"
<Where>
    <Eq>
        <FieldRef Name='FileLeafRef' />
        <Value Type='File'>foo.doc</Value>
    </Eq>
</Where>";

Searching in folders

If the document is in a folder, the above query would not be able to find it. In order to search inside a folder, you’d have to specify the folder:

query.Folder = list.ParentWeb.GetFolder(folderName);

More conveniently, you can simply allow the query to search recursively. The C# snippet is as follows:

SPQuery query = new SPQuery();
query.Query = @"
<Where>
    <Eq>
        <FieldRef Name='FileLeafRef' />
        <Value Type='File'>foo.doc</Value>
    </Eq>
</Where>";
query.ViewAttributes = "Scope = 'Recursive'";

If you have a lot of folders and documents, it would be more efficient to narrow down the search scope by specifying the parent folder if you know the folder name, rather than having the query search all folders.

Related posts: