Using Dictionary<string, object> for metadata

246 views
Skip to first unread message

ml.se...@medialabinc.com

unread,
Sep 4, 2016, 4:53:59 AM9/4/16
to RavenDB - 2nd generation document database
I'm curious to know if an approach I'm looking at taking is the proper way to use Raven.

Our company works with the homebuilding industry and while many of the concepts are similar, each one of our customers have different sets of data associated with each object.

For a basic example we have a Lot. A Lot has certain features common to all clients, but Client A needs "PerimeterLength" and "DrivewayOrientation" while Client B needs "FloodZoneRating", "IsRiverfront", and "FtAboveSeaLevel". Even worse, both clients may need "HOAFees" but one may need that as a boolean, while the other wants the actual dollar amount.

What I've done is basically add a Dictionary<string, object> Metadata property onto the object. This, of course, works wonderfully in Raven, saving out any random datapoint they want to throw at us. I've also created an index of

GetLotMetadata

from user in docs.Lots
from u in user.Metadata
select new { u.Key, u.Value } 

And can query in .Net using

session.Advanced.LuceneQuery<Lot>("GetLotMetadata")
.Where("Key:DrivewayOrientation")
.AndAlso()
.Where("Value:NorthWest");

Works like a charm. I get the objects I need.

My question is - is this the proper way to use RavenDb and are there going to be performance gotchas as clients add on a hundred data points on a thousand elements? I see that LuceneQuery is deprecated, so is there another way to perform this query?

Also, we have constraints on the extra data types (Metadata is probably the wrong word here, but it's what I've got for now) so the object side can never be more than primitive types or arrays of primitive types so it's not like we'll be storing complex objects of objects etc.

Thoughts? Better suggestions?

R


Oren Eini (Ayende Rahien)

unread,
Sep 4, 2016, 6:38:26 AM9/4/16
to ravendb
This is called a fanout, and it isn't a good idea.
You can look at dynamic fields, instead:



Hibernating Rhinos Ltd  

Oren Eini l CEO Mobile: + 972-52-548-6969

Office: +972-4-622-7811 l Fax: +972-153-4-622-7811

 


--
You received this message because you are subscribed to the Google Groups "RavenDB - 2nd generation document database" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

ml.se...@medialabinc.com

unread,
Sep 14, 2016, 11:40:10 AM9/14/16
to RavenDB - 2nd generation document database
Sorry for the long delay in a reply, for some reason this never showed up in my feeds.

Looking at the link, do I have to create an index for every property I want to look at? In the sample, you have
public class Products_ByAttribute : AbstractIndexCreationTask<Product> { public class Result { public string Color { get; set; } } ... 
Does that mean I have to have each field I want to query defined in the AbstractIndex? I'm not aware of the fields ahead of time to create this.

I tried this with a sample LINQPad 

void Main()
{
MyCustomDataClass mcdc = new MyCustomDataClass();
mcdc.Name = "First Test";
mcdc.CustomData.Add("Color", "Avocado");
mcdc.CustomData.Add("Price", 125.00);

var store = new Raven.Client.Document.DocumentStore
{
Url = "http://localhost:8889",
DefaultDatabase = "Playground_Robb"
};
store.Initialize();

new MyCustomClass_ByAttribute().Execute(store);

using (var session = OpenSession())
{
// session.Store(mcdc);
// session.SaveChanges();
IList<MyCustomDataClass> results = session
.Advanced
.DocumentQuery<MyCustomDataClass, MyCustomClass_ByAttribute>()
.WhereEquals("Price", 125.00)
.ToList();
results.Dump();
}
}

// Define other methods and classes here

public class MyCustomDataClass
{

public int Id { get; set; }
public string Name { get; set; }
public Dictionary<string, object> CustomData { get; set; } = new Dictionary<string, object>();

}

public class MyCustomClass_ByAttribute : AbstractIndexCreationTask<MyCustomDataClass>
{
public class Result
{
public string Color { get; set; }
}

public MyCustomClass_ByAttribute()
{
Map = products => from p in products
 select new
 {
 _ = p.CustomData
 .Select(attribute =>
 CreateField(attribute.Key, attribute.Value, false, true))
 };
}
}
and I can only get results for Price on WhereEquals. WhereGreater or any comparison field always returns 0 results. Is this because the result doesn't contain the Price property?
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.

Oren Eini (Ayende Rahien)

unread,
Sep 15, 2016, 12:54:15 AM9/15/16
to ravendb
No, you can do this dynamically, see:

Map = products => from p in products select new { _ = p.Attributes .Select(attribute => CreateField(attribute.Name, attribute.Value, false, true)) };
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages