Ravendb retrieve all documents in collection for reporting - lucene

I need to retrieve all documents from a collection to dump it to an Excel file.
Using this seems to work
var luceneQuery = Session.Advanced.LuceneQuery<Test.ReduceResult>("Test/ByTestData");
var enumerator = Session.Advanced.Stream(luceneQuery);
var obj = new List<Test.ReduceResult>();
while (enumerator.MoveNext())
{
obj.Add(enumerator.Current.Document);
}
This gives me all the results in the index.
But instead of index I want to retrieve all the documents in a collection (as the index does not contain all the information stored in the document).
How can this be done?

Change your query to be:
var luceneQuery = Session.Advanced.LuceneQuery<Test.ReduceResult>("Raven/DocumentsByEntityName")
.WhereEquals("Tag", "Customers");
This will give you all customers.

Related

Update typed object in CosmosDB

I want to update an document in CosmosDB, for this matter, I first retrieve the document and transform it to a typed object, like this:
public async Task<T> ReadRawAsync(Expression<Func<T, bool>> predicate)
{
var query = _client
.CreateDocumentQuery<T>(_uri)
.Where(predicate)
.AsDocumentQuery();
var results = new List<T>();
while (query.HasMoreResults)
results.AddRange(await query.ExecuteNextAsync<T>());
return results.FirstOrDefault();
}
After some transformations I want to update (replace) that document:
await _client.ReplaceDocumentAsync(_uri, document);
I am not completely sure this can be done in this way. Could you please point to what is required to do such an update?
ReplaceDocumentAsync will work only if the document has a property named id (notice the lower case, it needs to serialize to lowercase id, so you might need a JsonProperty("id")) and a document with this id must exist in the collection.
Also if your collection is partitioned then you need to provide the next object in this method which is the RequestOptions and add the PartitionKey value of this document in it.

Update Document with external object

i have a database containing Song objects. The song class has > 30 properties.
My Music Tagging application is doing changes on a song on the file system.
It then does a lookup in the database using the filename.
Now i have a Song object, which i created in my Tagging application by reading the physical file and i have a Song object, which i have just retrieved from the database and which i want to update.
I thought i just could grab the ID from the database object, replace the database object with my local song object, set the saved id and store it.
But Raven claims that i am replacing the object with a different object.
Do i really need to copy every single property over, like this?
dbSong.Artist = songfromFilesystem.Artist;
dbSong.Album = songfromFileSystem.Album;
Or are there other possibilities.
thanks,
Helmut
Edit:
I was a bit too positive. The suggestion below works only in a test program.
When doing it in my original code i get following exception:
Attempted to associate a different object with id 'TrackDatas/3452'
This is produced by following code:
try
{
originalFileName = Util.EscapeDatabaseQuery(originalFileName);
// Lookup the track in the database
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
if (dbTracks.Count > 0)
{
track.Id = dbTracks[0].Id;
_session.Store(track);
_session.SaveChanges();
}
}
catch (Exception ex)
{
log.Error("UpdateTrack: Error updating track in database {0}: {1}", ex.Message, ex.InnerException);
}
I am first looking up a song in the database and get a TrackData object in dbTracks.
The track object is also of type TrackData and i just put the ID from the object just retrieved and try to store it, which gives the above error.
I would think that the above message tells me that the objects are of different types, which they aren't.
The same error happens, if i use AutoMapper.
any idea?
You can do what you're trying: replace an existing object using just the ID. If it's not working, you might be doing something else wrong. (In which case, please show us your code.)
When it comes to updating existing objects in Raven, there are a few options:
Option 1: Just save the object using the same ID as an existing object:
var song = ... // load it from the file system or whatever
song.Id = "Songs/5"; // Set it to an existing song ID
DbSession.Store(song); // Overwrites the existing song
Option 2: Manually update the properties of the existing object.
var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.Artist = song.Artist;
existingSong.Album = song.Album;
Option 3: Dynamically update the existing object:
var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.CopyFrom(song);
Where you've got some code like this:
// Inside Song.cs
public virtual void CopyFrom(Song other)
{
var props = typeof(Song)
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(p => p.CanWrite);
foreach (var prop in props)
{
var source = prop.GetValue(other);
prop.SetValue(this, source);
}
}
If you find yourself having to do this often, use a library like AutoMapper.
Automapper can automatically copy one object to another with a single line of code.
Now that you've posted some code, I see 2 things:
First, is there a reason you're using the Advanced.DocumentQuery syntax?
// This is advanced query syntax. Is there a reason you're using it?
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
Here's how I'd write your code using standard LINQ syntax:
var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
.Where(t => t.Query == escapedFileName)
.Select(t => t.Id);
if (existingTrackId != null)
{
track.Id = existingTrackId;
_session.Store(track);
_session.SaveChanges();
}
Finally, #2: what is track? Was it loaded via session.Load or session.Query? If so, that's not going to work, and it's causing your problem. If track is loaded from the database, you'll need to create a new object and save that:
var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
.Where(t => t.Query == escapedFileName)
.Select(t => t.Id);
if (existingTrackId != null)
{
var newTrack = new Track(...);
newTrack.Id = existingTrackId;
_session.Store(newTrack);
_session.SaveChanges();
}
This means you already have a different object in the session with the same id. The fix for me was to use a new session.

Searching for href values with Lucene (Examine in Umbraco)?

I want to search for a href value with lucene/examine - more precise the 'locallink' value. Examine is straight out-of-the-box standard config.
I have the following snippet which does not return any results;
string searchQuery = "localLink:" + id;
UmbracoHelper helper = new UmbracoHelper(UmbracoContext.Current);
foreach (var result in helper.Search(searchQuery, false))
{
// Do something
}
Upon inspection of the index via Developer > Examine Management (in Umbraco backend), I can see that the index does contain the value I am trying to search for but under a "_Raw" property. So I guess the question is, how I can make my search, search in these fields also?
You made search with UmbracoHelper.
Try to use Examine Searcher as described in docs :
var searcher = ExamineManager.Instance.SearchProviderCollection["WebsiteSearcher"];
var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
var searchResults = searcher.Search(query);
http://our.umbraco.org/documentation/Reference/Searching/Examine/
http://umbraco.com/follow-us/blog-archive/2011/9/16/examining-examine.aspx

Fastest way to get the properties of umbraco documents

I am working on search functionality for a website designed through umbraco. I am using Examine to fetch the search results. Here is my code:
var Searcher = ExamineManager.Instance.SearchProviderCollection["ExternalSearcher"];
var searchCriteria = Searcher.CreateSearchCriteria(BooleanOperation.Or);
var query = searchCriteria.Field("tags", searchTerm.Fuzzy(0.5f)).Compile();
var searchResults = Searcher.Search(query);
With this method i can only get the nodes in which the search term belongs.But I want to directly fetch the whole value from the property.
I want to know what is the fastest way to fetch all the values from the same property in all the nodes.
I have finally managed to get the values directly from the property.This is the code I have used:
List<string> nodesList = new List<string>();
var Searcher = ExamineManager.Instance.SearchProviderCollection["ExternalSearcher"];
var searchCriteria = Searcher.CreateSearchCriteria(BooleanOperation.Or);
var query = searchCriteria.Field("tags", queryString.Fuzzy(0.5f)).Compile();
var searchResults = Searcher.Search(query);
foreach (var item in searchResults)
{
string paths = ((Examine.SearchResult)item).Fields["tags"];
nodesList.Add(paths);
}
using ((Examine.SearchResult)item).Fields["tags"] gets the property value directly.
If you want to costumize your search you need to define a new index set with the properties that you actually want to search on the /config/examineIndex.config file.
Quite well explained in this post.

Time out retrieving items from list

I have a problem retrieving items from a fairly large list. I can quickly and easily retrieve items from a small list with more or less 50 items, but when I try to retrieve items from a list containing more or less 4600 items, the sqlsever.exe process spikes for the duration of the request, but the items are never retrieved. If have set up the web applications throttling settings, so it can’t be that which is causing the problem. Here is the code that I originally used to retrieve the items. There is really nothing special to it.
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[uid.ToString()];
SPListItemCollection itemCollection = list.Items;
foreach (SPListItem i in itemCollection) //This is where the code stops responding
{
//Use list items
}
}
}
After that didn’t work, I tried a couple of other methods to retrieve the items from the list. Here is the code:
SPList list = web.Lists[uid.ToString()];
SPQuery query = new SPQuery();
query.Query = "";
query.QueryThrottleMode = SPQueryThrottleOption.Override;
SPListItemCollection itemCollection = list.GetItems(query);
//The code stops here
//I added this part for interest sake, i wanted to if it was the looping that caused the problem
//It seems the when you try to access properties of the item collection that the problem occurs
int itemCount = itemCollection.Count;
foreach (SPListItem i in itemCollection)
{
//Use list items
}
I also tried:
SPList list = web.Lists[uid.ToString()];
SPListItemCollectionPosition pos;
DataTable dt = list.GetDataTable(new SPQuery(), SPListGetDataTableOptions.None, out pos); //The code stops responding here
foreach (DataRow i in dt.Rows)
{
//Use data rows
}
Does anyone know what could be causing this problem?
Thank you in advance!
After a very long struggle we found a solution.
We found this post:
http://trycatch.be/blogs/tom/archive/2009/04/22/never-turn-off-quot-auto-create-amp-auto-update-statistics-quot.aspx
We tested it and it worked!!!
So all we had to do was switch "Auto create statistics" and "Auto update statistics" to true, and to problem was solved
Thanks for all the replys
You'll kill your server if you always try to retrieve all items either through list.Items, list.GetItems(query) (with an empty query).
You need to define a relevant query and specify the amount of results you want to retrieve through the RowLimit property of your SPQuery
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Title' /></OrderBy>"; // any relevant query here
query.RowLimit = 50;
Failing to do so will load all the items in memory prior to any other operation. You will probably kill your application pool available memory or your sql server memory when it will try to load all these data !
Hope that helped.
Try to get data using CAML query.
Once you have data you can put that in SPQuery.
Try to load the items not all at the same time. You can load them bulk wise (page wise) with the help of SPQuery.ListItemCollectionPosition (http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spquery.listitemcollectionposition.aspx).