RavenDb proximity search - ravendb

I have an entity type:
public class Log
{
public int Id { get; set; }
public string Action { get; set; }
public string Message { get; set; }
}
And my Index:
public class LogIndex : AbstractIndexCreationTask<Log>
{
public LogIndex()
{
Map = xs => from x in xs
select new
{
x.Id,
x.Action,
x.Message
};
}
}
And then I store an entity{ Action: "GetMessage", Message: "This is my Hello World message."}.
Then I can get this entity by Message:(Hello World) or Message:"Hello World" on Raven Studio.
Now I want to Proximity Search this entity by Message:(Hello World)~2, I get an exception unexpected tilde.
Then I use Message:"Hello World"~2, I get nothing.
What should I do? Thank you.

In order to support proximity search, you need to mark the Message as analyzed and use Message:"Hello World"~2

Related

Query entries by nested collection elements in RavenDB

I'm new to RavenDB and I'm struggling with this simple (i guess) issue.
I have a Subscriber with a collection of Subscriptions. And I want to make search by Subscription's fields, and return related Subscriber.
Here are simplified class examples:
public class Subscriber
{
public string Email { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public List<Subscription> Subscriptions { get; set; }
}
public class Subscription
{
public Guid Id { get; set; }
public string EventType { get; set; }
}
I've tried to make an index, as it is said in RavenDB docs:
public class Subscriber_BySubscription : AbstractIndexCreationTask<Subscriber>
{
public Subscriber_BySubscription()
{
Map = subscribers => from subscriber in subscribers
from subscription in subscriber.Subscriptions
select new
{
subscription.EventType,
subscription.QueueName
};
}
}
But I'm not sure that this is what I need, since query by collection using Select and Contains doesn't work. Moreover, the code looks so ugly that I feel that this is not the way how it should be.
So, I'd like to query Subscriptions by EventType, and have corresponding Subscriber as a result. In LINQ it would look like this: subscribers.Where(x => x.Subscriptions.Select(c => c.EventType).Contains(myEventType))
Managed to do it. Here is the right index:
public class Subscriber_BySubscription : AbstractIndexCreationTask<Subscriber>
{
public class Result
{
public string EventType { get; set; }
}
public Subscriber_BySubscription()
{
Map = subscribers => from subscriber in subscribers
from subscription in subscriber.Subscriptions
select new
{
subscription.EventType
};
}
}
And that's how it should be used:
var results = uow.Session
.Query<Subscriber_BySubscription.Result, Subscriber_BySubscription>()
.Where(x => x.EventType == eventType)
.OfType<Subscriber>()
.ToList();

Sorting on nested Id property

Let's say we have a document like this
public class Event
{
public string Id { get; set; }
public EntityDescriptor Venue { get; set; }
// Other properties omitted for simplicity
}
public class EntityDescriptor
{
public string Id { get; set; }
public string Name { get; set; }
}
And an index like this
public class Events : AbstractIndexCreationTask<Event>
{
public Events()
{
Map = items => from e in items
select new
{
Venue_Id = e.Venue.Id,
Venue_Name = e.Venue.Name
};
}
}
When trying to sort on Event.Venue.Id
session.Query<Event, Events>().Take(10).OrderBy(e => e.Venue.Id).ToArray();
the sent request is
/indexes/Events?&pageSize=10&sort=__document_id&SortHint-__document_id=String
Is this by design or a bug?
PS: OrderBy(e => e.Venue.Name) works as expected (sort=Venue_Name).
It's not a bug. __document_id is the special known field containing the ID of the document. It's there regardless of whether you have an .Id property.
edit
I misread your question. This indeed appears to be a bug. I recommend you send a simple repro case to the Raven forum and let them know which RavenDB version you're using.

NServiceBus saga Unique attribute

I have a saga data class with one property marked by Unique attribute. However, this didn't prevent NServiceBus from creating several sagas with identical values in this field.
Here is my data class:
public class ModuleAliveSagaData : ContainSagaData
{
[Unique]
public string ModuleId { get; set; }
public string Endpoint { get; set; }
public string Module { get; set; }
public DateTime LastCheck { get; set; }
public bool Warning { get; set; }
public bool Error { get; set; }
}
Here is the mapping:
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<ModuleAliveMessage>(m => m.Id).ToSaga(s => s.ModuleId);
}
Here is how data gets its values:
public void Handle(ModuleStartedMessage message)
{
Log.InfoFormat("Module {0} started on {1} at {2}", message.ModuleName, message.Endpoint, message.Timestamp);
Data.ModuleId = message.Id;
Data.Endpoint = message.Endpoint;
Data.Module = message.ModuleName;
Data.LastCheck = DateTime.Now;
Data.Warning = false;
Bus.SendLocal(new SendNotification
{
Subject = string.Format("Module {0} is online at {1}", Data.Module, Data.Endpoint)
});
RequestTimeout<ModuleCheckTimeout>(TimeSpan.FromMinutes(5));
Bus.Publish(new ModuleActivated
{
Endpoint = message.Endpoint,
Module = message.ModuleName
});
}
And here is what I see in the saga persistence table (Azure table storage):
Does it suppose to work like this or may be I am missing something?
Yves wrote this in comments, basically it is the proper answer:
Azure storage cannot check for uniquess besides the partitionkey/rowkey pair, so that attribute is ignored. If you need uniqueness you will have to consider another storage techology. PS: this is a known limitation of the underlying storage: http://github.com/Particular/NServiceBus.Azure/issues/21

RavenDb Select() downcasts instead of selecting the neccessary fields

public class PersonBrief
{
public int Id { get; set; }
public string Picture { get; set; }
public PersonBrief(Person person)
{
Id = person.Id;
Picture = person.Picture;
}
}
public class Person : PersonBrief
{
public string FullName { get; set; }
}
var results = session.Query<Person>()
.Select(x => new PersonBrief(x))
.ToList();
Assert.IsNull(results[0] as Person); // Fails
Is this a bug? If not, what would be the correct way to select only the fields i'm interested in?
It would work if you move the .ToList before the .Select, but that would be doing the work on the client.
If you want to do it on the server, you need to use As in your query, and you need a static index that does a TransformResults. See these docs.

RavenDb: Find movies that Actor X is NOT acting in

I'm new to RavenDb and I've encountered the following problem, which is pretty easy to solve in SQL databases, but not so easy in RavenDb (it seems).
Given my classes:
//document collection
public class Movie
{
public string Id { get; set; }
public string Title { get; set; }
public List<MovieActor> Actors { get; set; }
}
public class MovieActor
{
public string ActorId { get; set; }
public string CharacterName { get; set; }
public DateTime FirstAppearance { get; set; }
}
//document collection
public class Actor
{
public string Id { get; set; }
public string Name { get; set; }
}
Finding every movie that Leonardo DiCaprio is acting in is very easy and efficient with the following Map index:
public class Movies_ByActor : AbstractIndexCreationTask<Movie>
{
public Movies_ByActor()
{
Map = movies => from movie in movies
from actor in movie.Actors
select new
{
MovieId = movie.Id,
ActorId = actor.ActorId
};
}
}
But this is not what I want to achieve, I want the opposite... to find all the movies where Leonardo DiCaprio is not acting.
I have also tried the following query:
var leonardoActorId = "actor/1";
var movies = from movie in RavenSession.Query<Movie>()
where !movie.Actors.Any(a => a.ActorId.Equals(leonardoActorId))
select movie;
But this will only give me an exception:
System.InvalidOperationException: Cannot process negated Any(), see RavenDB-732 http://issues.hibernatingrhinos.com/issue/RavenDB-732
Anyone know how to achieve this the proper way in RavenDb ?
Using the method described in my blog post here:
http://www.philliphaydon.com/2012/01/18/ravendb-searching-across-multiple-properties/
You can create an index with an array of ActorIds:
public class Movies_ByActor : AbstractIndexCreationTask<Movie>
{
public Movies_ByActor()
{
Map = movies => from s in movies
select new
{
Actors = s.Actors.Select(x => x.ActorId)
};
}
public class ActorsInMovie
{
public object[] Actors { get; set; }
}
}
Then you can search where the movie doesn't contain the actor you want:
var result = session.Query<Movies_ByActor.ActorsInMovie, Movies_ByActor>()
.Where(x => x.Actors != (object)"actors/1")
.As<Movie>();
Since the object we're querying against is different to the result, we need to specify As<T> to tell RavenDB what the type of the object actually returned is.
Working sample: http://pastie.org/7092908