1
votes

in this post Return from first column of a categorized view when using readers fields I raised the issue that if I do getColumnValue(0) on a categorized view I just the unique category values, but because of Reader fields there could be categories that the user does not have access to the documents under it. The other option is to create a NotesViewNavigator and iterate through the navigator and build a treeMap of the values. My concern is that the view could contain thousands of entries and it would have to cycle through all the entries to build the category list which would typically have maybe 10 -12 entries.

So my question is what is the performance hit and scalability of the NotesViewNavigator process and/or is there a better way to get the categories in a view and recognize the users Reader rights.

New Edits

Can't seem to get this to work. I have a single categorized view and use this code WFSUtils.sysOut() simply prints to the console.

vw.setAutoUpdate(false);
var nav:NotesViewNavigator = vw.createViewNav();
nav.setEntryOptions(NotesViewNavigator.VN_ENTRYOPT_NOCOUNTDATA);
nav.setBufferMaxEntries(400);
nav.setMaxLevel(0);
var rtn:java.util.TreeMap=new java.util.TreeMap();
var entry:NotesViewEntry = nav.getFirst();
try{
while (entry != null){
    WFSUtils.sysOut("Entry not null");
    var thisCat:String = entry.getColumnValues().firstElement().toString();
    WFSUtils.sysOut("thisCat = " + thisCat);
    rtn.put(thisCat,"Nothing");
    WFSUtils.sysOut("did put " + thisCat)
    var tEntry:NotesViewEntry = nav.getNextCategory(entry);
    entry.recycle();
    entry = tEntry;
    tEntry.recycle();
}
viewScope.put("vsCats", rtn.keySet());
}catch(e){
    WFSUtils.sysOut("Error in getCategory " + e.toString())
}

the console print out is this:

25/08/2014 11:47:36 AM HTTP JVM: Get Navigator 25/08/2014 11:47:36 AM HTTP JVM: Entry not null 25/08/2014 11:47:36 AM HTTP JVM: thisCat = Approved~Bill Fox^WFS Automated Back end Process Example 25/08/2014 11:47:36 AM HTTP JVM: did put Approved~Bill Fox^WFS Automated Back end Process Example 25/08/2014 11:47:36 AM HTTP JVM: Error in getCategory Method NotesViewNavigator.getNextCategory(lotus.domino.local.ViewEntry) not found, or illegal parameters

The view has 9 categories so I would expect it to do 9 getNextCategories. I changed it to do getNext and the console out put is:

25/08/2014 11:52:42 AM HTTP JVM: Get Navigator 25/08/2014 11:52:43 AM HTTP JVM: Entry not null 25/08/2014 11:52:43 AM HTTP JVM: thisCat = Approved~Bill Fox^WFS Automated Back end Process Example 25/08/2014 11:52:43 AM HTTP JVM: did put Approved~Bill Fox^WFS Automated Back end Process Example 25/08/2014 11:52:43 AM HTTP JVM: Entry not null 25/08/2014 11:52:43 AM HTTP JVM: Error in getCategory Exception occurred calling method NotesViewEntry.getColumnValues() 25/08/2014 11:52:43 AM HTTP JVM: null

so it fails on the getColumnValues which worked on the first time through but not the second - not sure where the JVM: null is coming from. any ideas greatly appreciated.

2
There's a separate danger in getColumnValues().getFirstELement() if the view has date/times in it. C++ handles are required for them, but they're not children of the ViewEntry, so they're not recycled when recycling the ViewEntry. See intec.co.uk/the-perils-of-getcolumnvalues-get0 - Paul Stephen Withers

2 Answers

3
votes

No, I don't think you have to cycle through all the entries. Without having Domino Designer at hand right now, this is a bit of a rough guess (usually I do a quick test drive before answering here), but I'm quite confident it should work like this:
Just get to the first entry which in your case must be a category, then use .getNextSibling or .getNextCategory (careful if the view has multiple category levels!) jumping from category to category, and skipping all the other entries.
Depending on how the view index is set up, you might also check if there are any children available.

Just to be complete: make sure you set the parent view's AutoUpdate property to false; depending on the size of the view you might also want to experiment with various cache sizes; and of course don't forget to recycle, but you know that, I guess ;)

See also here (= AutoUpdate), here (= recycle properly) and here (= performance tip).

Hope this helps

6
votes

It looks like the View-design-level option "Don't show empty categories" does this for you - I'd previously assumed it was just a tip-off to the client to hide them, but it looks like it affects the behavior of ViewNavigator as well (which otherwise would show the full categories as well).

Once you have that checked, something like this may do the trick:

List<String> categories = new ArrayList<String>();
View view = database.getView("Some View");
view.setAutoUpdate(false);
ViewNavigator nav = view.createViewNav();
nav.setEntryOptions(ViewNavigator.VN_ENTRYOPT_NOCOUNTDATA);
nav.setBufferMaxEntries(400);
nav.setMaxLevel(0);
ViewEntry entry = nav.getFirst();
while (entry != null) {
    Vector<?> columnValues = entry.getColumnValues();

    String category = String.valueOf(columnValues.get(0));
    categories.add(category);

    entry.recycle(columnValues);
    ViewEntry tempEntry = entry;
    entry = nav.getNext();
    tempEntry.recycle();
}

I believe that that should be the fastest/safest way to do it at that point. setMaxLevel(0) means that the first/next operations will include only categories (or whatever is your top level), while the other ViewNavigator settings are for performance tweaking.