TDIing out loud, ok SDIing as well

Ramblings on the paradigm-shift that is TDI.

Saturday, September 22, 2012

A View to an NSF

Let's say you have a Notes Document with a lot of fields, including some fat ones - like rich text, images and other wads of data. Even if you are only interested in a subset of the fields, iterating can be agonizingly slow since the TDI Notes Connector retrieves the entire Document for each Entry returned. However, if there is a View available that contains the fields you need then there is a way around this that Rick Chapman and I discovered.

Start with your Notes Connector in Iterator mode, configured so that it is ready to pull Documents from your nsf. Then you add some Hook script magic to do the following:
  1. As part of Connector initialization (or just after), use the open Domino database to get access to your View; For example, in the Prolog - After Initialize Hook of your Notes Iterator. Here you retrieve the View Entries and the list of columns (fields) in the view.
  2. Instead of letting the Notes Connector retrieve Documents via its own getNext() functionality, you implement your own Entry retrieval logic by coding the Override GetNext Hook. This script grabs the next View entry and puts the columns in the Work Entry as attributes.
Here is some sample script for these Hooks to get you going. Remember to replace stuff like viewName with your own values.

Prolog - After Initialize:                                                                           
// first get the Connector Interface (Notes Connector) in a handy variable
 var dom = thisConnector.getConnector()

// This gets a reference to the db using the 'Database' param of the Connector
var db = dom.getDominoDatabase(dom.getParam("Database"))

// Note that any \ in the View name must be changed to /
// Some notes about the View-related objects and methods
//   views = db.getViews() returns all views for db
//   views.length returns the number of views
//   viewEntry.getColumnValues() gives you all the column values for this View entry
//   view.getColumns() returns the column names
var viewName = "98. Admin/DB2 Engagement Form Sync"
var view = db.getView(viewName);

// Prepare our entry counter. The first time around in the Override GetNext Hook we
// will return the first entry of the View, and on subsequent cycles we'll grab the next entry.
var counter = 0

// Retrieve the view entries
var col = view.getAllEntries()

// Get the column names
var colname_vec=view.getColumnNames()

Override GetNext:                                                                                      
if (counter == 0) {
    viewEntry = col.getFirstEntry()
else {
    viewEntry = col.getNextEntry()
}

// check for End Of Data (EOD)
if (myEntry == null) { 
    result.setStatus(0) // signals EOD
    return // exit the Hook and end Iteration
else {
    result.setStatus(1) // this means there is still data available
}

counter++ // must remember to increment our entry count

// Display a read status message for every 200 entries
if (counter % 200 == 0 ) {
    task.logmsg(thisConnector.getName() + " entry count: " + counter)
}

// Return all column values
vec = viewEntry.getColumnValues()

// Overriding GetNext means no Input Map, so the column fields must be put in the Work Entry here
for (i = 0; i < vec.length; i++) {
    work[colname_vec.elementAt(i)]= vec.elementAt(i)
}


And that's all there is to it! And note, gentle reader, that I have not tested this code - simply copy/pasted it from a project I assisted with. So if you find any problems here then please let me know and I will rectify this post :) Thanks!!