Filtering
To retrieve the files you are interested in, you need to define a set of conditions that they should match. To build a query with filtering criteria, you can use a bunch of available methods.
Where
The first method to create a conditional query is Where
which takes a string parameter. You need to manually define the whole query according to the Lucene syntax, the same as for the SearchAsync
command. This approach enjoys the full support of the Lucene search functionality. You can query the built-in RavenFS fields as well as the custom files' metadata.
List<FileHeader> results = await session.Query()
.Where("__fileName:readme* AND Copyright:HR")
.ToListAsync();
WhereEquals
It allows you to find the exact match on a file property or metadata. The following query will return all files that have the Copyright
metadata with HR
value.
List<FileHeader> results = await session.Query()
.WhereEquals("Copyright", "HR")
.ToListAsync();
WhereIn
Can be used to check a single value against the multiple values. For example, to get all the files that name is either readme.txt
or help.doc
, you can issue the following query:
List<FileHeader> results = await session.Query()
.WhereIn(x => x.Name, new[] { "readme.txt", "help.doc" })
.ToListAsync();
WhereStartsWith
In order to find the files that have metadata value starting with the specified prefix, use the WhereStartsWith
method. The below code will return all the files located in the /movies/ravenfs
directory and its subdirectories.
List<FileHeader> results = await session.Query()
.WhereStartsWith(x => x.FullPath, "/movies/ravenfs")
.ToListAsync();
WhereEndsWith
Analogously, you can build a query that will look for the files with a given suffix value. For example, this can be used to find files of the same type by using file extensions.
List<FileHeader> results = await session.Query()
.WhereEndsWith(x => x.Name, ".txt")
.ToListAsync();
WhereLessThan and WhereLessThanOrEqual
While querying numeric metadata values, methods such as WhereLess
or WhereBetween
come in handy. You can use them to determine a file size as well as to query the numeric custom metadata fields.
List<FileHeader> results = await session.Query()
.WhereLessThan(x => x.TotalSize, 1024)
.ToListAsync();
List<FileHeader> results = await session.Query()
.WhereLessThanOrEqual("Downloaded", 5)
.ToListAsync();
WhereGreaterThan and WhereGreaterThanOrEqual
Note that you can even apply such query on a string field - then values will be compared lexicographically.
session.RegisterUpload("test.file", stream);
session.RegisterUpload("test.fil", stream);
session.RegisterUpload("test.fi", stream);
session.RegisterUpload("test.f", stream);
await session.SaveChangesAsync();
List<FileHeader> results = await session.Query()
.WhereGreaterThan(x => x.Name, "test.fi") // will return 'test.fil' and 'test.file'
.ToListAsync();
List<FileHeader> results = await session.Query()
.WhereGreaterThanOrEqual("Download-Ratio", 7.3)
.ToListAsync();
WhereBetween and WhereBetweenOrEqual
Use the WhereBetween
method to find files that fulfill a range criteria.
List<FileHeader> results = await session.Query()
.WhereBetween(x => x.TotalSize, 1024 * 1024, 5 * 1024 * 1024) // size has to be > 1KB but < 5KB
.ToListAsync();
List<FileHeader> results = await session.Query()
.WhereBetweenOrEqual("NumberOfDownloads", 5, 10)
.ToListAsync();
ContainsAll and ContainsAny
Note that under a single metadata key, there can be multiple values stored as an array. For example, you can store multiple attributes in the metadata:
session.RegisterUpload("git.bin", content, new RavenJObject()
{
{"Attributes", new RavenJArray(new object[]{ "r", "w" }) }
});
session.RegisterUpload("svn.bin", content, new RavenJObject()
{
{"Attributes", new RavenJArray(new object[]{ "w", "x" }) }
});
await session.SaveChangesAsync();
In order to allow queries execution against array values, you can use ContainsAll
to determine that all provided values have to be in the array:
List<FileHeader> results = await session.Query()
.ContainsAll("Attributes", new[] { "r", "w" }) // will return git.bin
.ToListAsync();
The ContainsAny
method checks just for an occurrence of any value from the specified collection:
List<FileHeader> results = await session.Query()
.ContainsAny("Attributes", new[] { "r", "x" }) // will return git.bin and svn.bin
.ToListAsync();
AndAlso and OrElse
So far we have considered queries with a single condition. However, you may want to build a more complex query by providing multiple predicates. Let's take a look at the example:
List<FileHeader> results = await session.Query()
.WhereStartsWith(x => x.Name, "readme")
.WhereEquals("Copyright", "HR")
.ToListAsync();
It will send the following query to the server:
__fileName:readme* Copyright:HR
Note that between these two conditions there is no logical operator. In that case, the OR operator will be used, as it is the default Lucene conjunction operator.
However, if your intention is to retrieve files that match both conditions, you should explicitly indicate that by using the AndAlso
operator.
List<FileHeader> results = await session.Query()
.WhereStartsWith(x => x.Name, "readme")
.AndAlso()
.WhereEquals("Copyright", "HR")
.ToListAsync();
Then the query sent to the server will look as follows:
__fileName:readme* AND Copyright:HR
Sometimes you may need to explicitly indicate that you want to join criteria by using OR operator. In that case, join your predicates using the OrElse
method:
List<FileHeader> results = await session.Query()
.WhereIn(x => x.Name, new[] { "help.txt", "documentation.doc" })
.OrElse()
.WhereStartsWith(x => x.Name, "readme")
.ToListAsync();
The actual query will be:
@in<__fileName>:(help.txt,documentation.doc) OR __fileName:readme*
OnDirectory
This method is used to indicate the directory where the search should be performed. Additionally, you can determine whether the search operation should be run only against this directory or also its subfolders.
List<FileHeader> results = await session.Query()
.OnDirectory("/documents/wallpapers", recursive: true)
.WhereEndsWith(x => x.Name, "1920x1080.jpg")
.ToListAsync();