Map reduce returns old data

Viewed 82

I have the following map:

from doc in docs
select new {Name = doc.Name, Count = 1}

reduce

from result in results
group result by new {result.Name}
into g
select new {
Name =  g.Key.Name,
Count = Enumerable.Sum(g, x => ((int) x.Count))
}

If I put a lock on the index folder and then save a document and then delete the document and resave the document to trigger a reindex the old document still appears in the index query results despite the index being reported as up to date. The last indexed date is also older than the date the document was updated so therefore the index should not contain any old results.

Any ideas what's going on? This is actually part of a large problem I've discovered on a production system. I'm not clear why it's happening but I've been able to reproduce a similar situation by locking the index so I suspect there's some process causing the lock. It means the index results return projections that are old.

How can I get the reduce to filter out results that are old?

2 Answers

If you disabled the index and the documents are updated/deleted. You'll get outdated results from the map-reduce index. This can happen even when the index isn't disabled.

The reason is that indexes are eventual consistent. You can read about it here: https://ravendb.net/docs/article-page/3.5/Csharp/users-issues/understanding-eventual-consistency

You can use WaitForNonStaleResultsAsOfLastWrite: https://ravendb.net/docs/article-page/2.5/Csharp/client-api/querying/stale-indexes#setting-cut-off-point

What you're describing is stale indexes: you update/create/delete a document and immediately queried for the document, but the query returns stale results.

The recommended way to fix this is by calling .WaitForIndexesAfterSaveChanges() during your create/update/delete calls:

// Inform Raven you'll wait for indexes when calling .SaveChanges
session.Advanced.WaitForIndexesAfterSaveChanges(
    timeout: TimeSpan.FromSeconds(30),
    throwOnTimeout: false);

// Do your update.
session.Store(new Employee
{
    FirstName = "John",
    LastName = "Doe"
});

// This won't return until affected indexes are updated.
session.SaveChanges();

// Now you can run a query against your index, and it will return the updated data.
...

This way, .SaveChanges will block until the indexes are updated. Run your query immediately after .SaveChanges and you'll see the updated results as expected.

Related