Question

I have a situation where I want to do a query by two fields, I thought this would be pretty simple, but it is proving a great deal more difficult than I thought.

This is a rough look at the document being queried...

class Item {
   string Id { get; set; }
   string Name { get; set; }
   Origin Origin { get; set; }
}

class Origin {
   string Id { get; set; }
   string Name { get; set; }
}

There are other fields, of course. I am just listing the relevant ones. So my Index looks like this.

public class Item__ByName : AbstractIndexCreationTask<Models.Items.Item, Item__ByName.Result> {

    public class Result {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Origin { get; set; }
    }

    public Item__ByName() {
        Map = items => from item in items
                       select new Result {
                           Id = item.Id,
                           Name = item.Name,
                           Origin = item.Origin.Name
                       };

        Index(i => i.Name, FieldIndexing.Analyzed);
        Index(i => i.Origin, FieldIndexing.Analyzed);
    }
}

And then I attempt to query it like this...

var results = RavenSession
    .Query<Models.Items.Item, Indexes.Item__ByName>()
    .Where(n => n.Name == name)
    .Where(n => n.Origin.Name == origin)
    .ToList();

but it keeps telling me that "Origin_Name" is not defined. I am really confused about why it is saying this, when I've very clearly defined it.

Was it helpful?

Solution

A couple of things:

  • Index entry names cannot be nested. Even though the document has structure, the index is flat. To compensate for this, Raven uses the convention of replacing periods with underscores. So in your index definition, you have to name your field Origin_Name to match.

    Origin_Name = item.Origin.Name
    
  • There's hardly ever a need to include the Id in the index map. It is handled differently behind the scenes, so it's included by default.

  • You don't need a Result class in this scenario, because you aren't storing these fields or using them in a map/reduce.

  • If you plan on doing a partial match, or a search, then having the fields analyzed is fine. If you are only doing a whole string match, then you shouldn't analyze the fields.

  • You should combine your Where queries into a single clause:

    .Where(n => n.Name == name && n.Origin.Name == origin)
    

    Alternatively, you can use the Intersection Queries feature:

    .Where(n => n.Name == name)
    .Intersect()
    .Where(n => n.Origin.Name == origin)
    
  • This particular query is simple enough that if you wanted you could omit the static index and Raven would create one for you automatically.

OTHER TIPS

You can also use .And() and .Or() between two where's especially when you use advance query with LuceneQuery Object

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top