Reputation: 526
UPDATE: Thanks funql/Kim. I understand the point you're making - so if you'll allow me a follow-up question, is there in fact a way of doing object persistence (as suggested by Funql for Mongo) using Couch? As far as I understood before starting this project, this was one of the benefits of NoSQL DB's - that you don't need to worry about DAO layers, you can pretty much dump an object into a Document and pull it out as needed, no hassle, leaving the schema definition to be entirely implied by your class definition, and I can't see a fundamental reason why it would work in MongoDB but not CouchDB?
I'm using CouchDB for the first time in an enterprise application, and it feels like I'm missing something fundamental about the NoSQL mindset.
Suppose you have the following Java classes:
public class Customer { ... }
public abstract class Product { ... } // could just as well be an interface
public class ProductA extends Product { ... };
public class ProductB extends Product { ... };
public class Sale {
private String transactionId;
private Customer customer;
private List<Product> items;
// ...
}
When storing a Sale into a Couch database (or other document-store DB for that matter), I end up with a single document containing the entire Sale, which is what I want. However, I hit a problem the moment I start trying to store/retrieve abstract classes or classes which implement an interface. My Sale record typically looks something like this (simplified):
{
"transactionId": "12345",
"customer": { "name": "Joe Soap" },
"items": [
{
"name": "Coke",
"price": 12.99,
"qty": 1
},
{
"name": "Minced meat",
"weight": 1.23,
"price": 49.99
}
]
}
Now retrieving that data is simple for the case of the customer - I can use a custom serializer/deserializer and use reflection to tell that Sale.customer
is an instance of Customer
, instantiate an instance, and set its fields from the JSON data.
However, this becomes much more tricky with the items
record, since I have no idea which subclass of Product
to instantiate for each element in the list (and I can't initialize an instance of an abstract class or an interface).
I've tried to work around this by storing the full class name with the data (e.g. each Product
record would contain an additional @class
field to indicate what type of object was serialized, and so what type should be initialized while deserializing) but this means that I'm creating a problem for myself if I ever, for example, move that class to a different package (as the stored @class
value will then be invalid). While this could be mitigated with migration scripts (or other approaches) it feels as if I'm missing a fundamental point and am hacking around it.
Can somebody please tell me what it is that I'm doing wrong? Is there a more elegant approach to this which will allow me to not have to fiddle as much with the serialization code, since my understanding is that NoSQL databases are supposed to reduce the amount of time developers need to spend writing persistence code?
For what it's worth, I've tried using Ektorp and LightCouch, and have had similar issues with both.
Upvotes: 2
Views: 569
Reputation: 81
this is a typical problem of object-relational mapping. It is not a problem that is limited to document databases.
There are three approaches you can choose:
In my experience, most people opt for alternative 2, because they want to keep the database independent of the application details (classes/packages).
In an ealier application, where I had the same problem I simply maintained a mapping table just for those classes that have moved. Easy to do.
If you do not want to fiddle with the serialisation code, then you can use any of the object-persistence frameworks available for MongoDB.
Upvotes: 2