Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Querying Raven with Where() only filters against the first 128 documents?

Tags:

lucene

ravendb

We're using Raven to validate logins so people can get into our site.

What we've found is that if you do this:

// Context is an IDocumentSession 
Context.Query<UserModels>()
           .SingleOrDefault(u => u.Email.ToLower() == email.ToLower()); 

The query only filters on the first 128 docs of the documents in Raven. There are several thousand in our database, so unless your email happens to be in that first 128 returned, you're out of luck.

None of the Raven samples code or any sample code I've come across on the net performs any looping using Skip() and Take() to iterate through the set.

  1. Is this the desired behavior of Raven?
  2. Is it the same behavior even if you use an advanced Lucene Query? ie; Do advanced queries behave any differently?
  3. Is the solution below appropriate? Looks a little ugly. :P

My solution is to loop through the set of all documents until I encounter a non null result, then I break and return .

public T SingleWithIndex(string indexName, Func<T, bool> where)
{
    var pageIndex = 1;
    const int pageSize = 1024;
    RavenQueryStatistics stats;

var queryResults = Context.Query<T>(indexName)
    .Statistics(out stats)
    .Customize(x => x.WaitForNonStaleResults())
    .Take(pageSize)
    .Where(where).SingleOrDefault();

if (queryResults == null && stats.TotalResults > pageSize)
{
    for (var i = 0; i < (stats.TotalResults / (pageIndex * pageSize)); i++)
    {
        queryResults = Context.Query<T>(indexName)
            .Statistics(out stats)
            .Customize(x => x.WaitForNonStaleResults())
            .Skip(pageIndex * pageSize)
            .Take(pageSize)
            .Where(where).SingleOrDefault();

        if (queryResults != null) break;

        pageIndex++;
    }

}

return queryResults;

}

EDIT:

Using the fix below is not passing query params to my RavenDB instance. Not sure why yet.

Context.Query<UserModels>()
    .Where(u => u.Email == email)
    .SingleOrDefault();

In the end I am using Advanced Lucene Syntax instead of linq queries and things are working as expected.

like image 812
Jason Slocomb Avatar asked Feb 24 '11 01:02

Jason Slocomb


1 Answers

RavenDB does not understand SingleOrDefault, so it performs a query without the filter. Your condition is then executed on the result set, but per default Raven only returns the first 128 documents. Instead, you have to call

Context.Query<UserModels>()
       .Where(u => u.Email == email)
       .SingleOrDefault();

so the filtering is done by RavenDB/Lucene.

like image 66
Thomas Freudenberg Avatar answered Sep 21 '22 08:09

Thomas Freudenberg