3

I am new to CouchDB and Ektorp (I ACTUALLY started today to try to work with it). The most detailed documentation I have found to help me getting started is this one:

http://www.ektorp.org/reference_documentation.html#d100e394

My use case is that I want to save a very complex class as a document (I have managed that so far), but I do not want to load all the fields all the time (since some of those are potentially big collections of other simpler documents).

Here is an example of what I have (its just an experimental class I am using to learn to use Ektorp and CouchDB

@JsonSerialize(include = Inclusion.NON_NULL)
public class Player extends CouchDbDocument {

    private int xp = 0;

    @JsonDeserialize(using = CoinPouchDeserializer.class)
    private CoinPouch coins = new CoinPouch(); // subclass of enumMap not
                           // complex
    @DocumentReferences(backReference = "playerId", fetch = FetchType.LAZY, descendingSortOrder = true, orderBy = "itemid")
    private Inventory inventory = new Inventory();// subclass of Map<String,
                          // Item> Items are document
                          // themselves
}

I manage to save it and get it by id just fine. But how to I get it without loading it inventory?
I would also appreciate any link to other resources I should checkout about starting to use couchdb or ektorp with java (or scala), cheers.

Thanks for any helpful answer.

le-doude
  • 3,345
  • 2
  • 25
  • 55

1 Answers1

1

Document references like these basically act similarly to JOINs in a SQL DB, but you can't do a JOIN in one request as you can with SQL. Instead you need to make first request to get the core document you're looking for, and then a second request to get any referenced documents.

Setting FetchType to eager tells Ektorp to do this as soon as you read the first document, so a series of requests are then made immediately for all referenced documents, ensuring everything is loaded before you start using it. FetchType lazy doesn't do this, and instead ignores referenced documents until you try and use them.

Generally you want lazy loading if it's unlikely you're going to be using the referenced documents. If you're always going to be using them eager loading is probably better, as it does at least give you a consistent up-front loading time, rather than having requests made unpredictably later in the process. By the sound of it you don't want to load the inventory when you load a player though, so yes, setting FetchType to lazy should solve that problem.

Meanwhile the cascade parameter lets you configure what happens to referenced documents if you perform operations (update delete etc) on this document. By default referenced documents need to be explicitly saved or deleted themselves, you can't just save the main document and expect the others to be saved too. By the sound of it that's actually the behaviour you want anyway (as otherwise saving a change to the player will load and then save the inventory, I believe).

Also you should note that your example isn't actually valid, according to the documentation, as you can only use DocumentReferences to refer to Sets (actual bonafide Java Set implementations) of other documents, and yours is a Map.

Tim Perry
  • 11,766
  • 1
  • 57
  • 85
  • What if the items in the inventory are not documents and I do not reference them? Could I load Player without his inventory field? Could I tell ektorp to do that? And how? – le-doude Apr 12 '13 at 13:02
  • Yes, you can completely drop the field from being included in documents if you mark is with `@JsonIgnore`. Is that what you mean? If they're not documents and you don't want to store this relationship in CouchDB then you don't need the `@DocumentReferences` annoatation at all though anyway. – Tim Perry Apr 12 '13 at 13:38
  • Mmmmh no I would like something like: Player p = db.get(Player.class, "key", new String[]{"inventory"}); to ignore the inventory for _that_ call. And only that call. Would that be possible or do I have to load the whole document all the time. – le-doude Apr 12 '13 at 13:40
  • You could, I think, have Player class marked with `@JsonIgnoreProperties` and a PlayerWithInventory subclass, where only the subclass has an Inventory field. Loading with db.get(Player.class, "key") will then load just the player and ignore the rest, and loading with db.get(PlayerWithInventory.class, "key") will load the full thing. Have to be careful have you save again with this though or you'll existing inventory fields. Anyway, this isn't really part of Ektorp itself; the JSON -> Java objects step is managed by Jackson (http://wiki.fasterxml.com/JacksonHome) – Tim Perry Apr 12 '13 at 15:06
  • There would be no point. I am trying to prevent couchdb to send me those fields (to save time). If I just ignore it on my app then couchdb is the same as reading blobs from cassandra or redis. – le-doude Apr 12 '13 at 15:08
  • 1
    Ah, I see. You can't directly just do that with CouchDB. Those fields either need to be in a separate document, and you can use `@DocumentReferences` and FetchType lazy, or you need to define a view in CouchDB that returns documents without their inventories, and read from there instead. – Tim Perry Apr 12 '13 at 15:44
  • I reformulated my situation in another question: http://stackoverflow.com/questions/15976886/how-to-tell-ektorp-couchdb-to-not-return-fields-of-a-document Could you give it a look? – le-doude Apr 12 '13 at 17:17