dominoGuru.com

Latest Updates

Loading... Please Wait!

Products & Applications

Showtime
My Blackberry Enterprise Server Push Utility for the Lotus Notes Client, allows you to create Jobs for individual Channel, Message, and Browser Content Pushes, as well as allows you to delete Pushed Channel Icons from defined recipient devices.

Time Tracker
The idea is simple. At the start of your day - upon completion of your first task - create an entry highlighting what you did and whether you feel it was an efficient or inefficient use of your time. Based on several requests, you can also select the priority, apply categories, or even align your time against a project.

For Lotus Notes Client v8.0 and above, you can use the Time Tracker Widget to make this process even easier!

Zephyr
My Configuration-based Rich Text Mail Merge and Emailing Utility, Zephyr allows you to create rich, data-driven emails to support automated workflow - all via Microsoft Word Mail Merge-like architecture. Dear <firstname> allows you to personalize each email message not only to the individual recipient, but also to the individual application workflow event!

xCopy
xCopy is a simple configurable xCopy client for the Lotus Notes client. By creating and defining xCopy Profiles, you can batch process your file backup or remote upload jobs. With the addition of the xCopy sidebar widget, you can easily kick-off these jobs, and modify both the xCopy Profiles and xCopy itself.

Community & Resources

Lotus Technical Information & Education Community

The Lotus Technical Information & Education community is comprised of IBM, business partner, and customer subject matter experts who use product wikis, published articles, white papers, community blogs and the latest in social media to build and share high quality technical content.

OpenNTF.org - Open Source Community for Lotus Notes Domino

OpenNTF is devoted to enabling groups of individuals all over the world to collaborate on IBM Lotus Notes/Domino applications and release them as open source.

developerWorks Lotus : Wikis

Share your deployment experiences and best practices in our wikis and help IBM to create scenarios for successful deployments. Contribute to the community by collaborating on shared content and leverage the shared knowledge from that community.

Simple LotusScript NotesDocumentCollection Iteration

02/16/2010 12:21:31 PM by Chris Toohey

They grow up so fast... Sometimes a StampAll just doesn't give you enough flexibility or control when dealing with a NotesDocumentCollection. Sometimes you need to some logic behind each NotesDocument update. For those situations, we tend to use a technique called iteration... which sounds really awesome and consultant-like, but basically boils down to creating a looping function within your LotusScript.

There are several methods complete with built-in functions in LotusScript that allow you to iterate through NotesDocumentCollections, NotesViewEntryCollections, and such... so I'll start off by defining a simple use case, and then showing you how not to iterate through a given NotesDocumentCollection, and then ultimately showing you a solid approach to NotesDocumentCollection iteration!

Use Case

A scheduled Agent for a simple Project Management application will evaluate each new NotesDocument since last run and -- since we're going for simple here -- update the manager NotesItem with the value stored in the submitter's Person Document in the Domino Directory. Since this is an ideal world, every Person Document manager is both defined and contains the common name matching the manager's own Person Document.

Author's Note: Yeah, this would never happen, but this is a use case for iteration, not chasing down the manager NotesItem values... so go with me on this one.

How not to...

The below LotusScript uses the getNthDocument function to loop through a supplied NotesDocumentCollection and perform whatever NotesDocument application logic is needed (in this case, a Domino Directory lookup and NotesDocument update & save).

Function setManager(col As NotesDocumentCollection) Dim s As New NotesSession Dim counter As Integer Dim doc As NotesDocument Dim nab As New NotesDatabase(s.CurrentDatabase.Server, "names.nsf") Dim nabview As NotesView Dim nabcol As NotesDocumentCollection Dim nabdoc As NotesDocument Set nabview = nab.GetView("people") counter = 0 Set doc = col.GetFirstDocument Do Until(counter > col.Count) Set doc = col.GetNthDocument(counter) Set nabcol = nabview.GetAllDocumentsByKey(Join(doc.GetItemValue("submitter"), ""),True) Set nabdoc = nabcol.GetFirstDocument Call doc.ReplaceItemValue("manager", nabdoc.GetItemValue("manager")) Call doc.Save(True, False, True) counter = counter + 1 Loop End Function

This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.

If you have 5 NotesDocuments, this isn't that bad of an approach. I still wouldn't use it though and the reason is pretty simple: it scales horribly, and we're coding for the species here people!

The reason it scales so poorly is simply that the use results in the code losing it's place through the iteration. As a result, it starts from the first NotesDocument in the NotesDocumentCollection and steps through... the whole time asking it it's the Nth NotesDocument in the NotesDocumentCollection.

How To

Function setManager(col As NotesDocumentCollection) Dim s As New NotesSession Dim doc As NotesDocument Dim nab As New NotesDatabase(s.CurrentDatabase.Server, "names.nsf") Dim nabview As NotesView Dim nabcol As NotesDocumentCollection Dim nabdoc As NotesDocument Set nabview = nab.GetView("people") Set doc = col.GetFirstDocument Do Until(doc Is Nothing) Set nabcol = nabview.GetAllDocumentsByKey(Join(doc.GetItemValue("submitter"), ""),True) Set nabdoc = nabcol.GetFirstDocument Call doc.ReplaceItemValue("manager", nabdoc.GetItemValue("manager")) Call doc.Save(True, False, True) Set doc = col.GetNextDocument(doc) Loop End Function

This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.

Not a big change here, but using the getNextDocument steps through the NotesDocumentCollection and scales much better than the dreaded getNthDocument.

Conclusion

So what have we learned?

  1. There's no environment in the world where the above scenario would actually exist.
  2. I suck at creating Use Cases...
  3. getNthDocument is evil. If you come across it in your production code, you might as well just unplug the Domino server.
  4. getNextDocument-based iterations scale!

And, most importantly, NotesDocumentCollection iteration is an extremely powerful technique that can allow you to process large numbers of NotesDocuments with applied logic at the individual NotesDocument-level.

 
Mark HughesName:Mark HughesWebsite:http://hughesconnect.comComment

i always used

while not(doc is nothing)

wend

Dan SicklesName:Dan SicklesComment

Mark, Do (While | Until) lets you use Exit Loop or add it later without changing the loop syntax.

David LeedyName:David LeedyWebsite:http://notesin9.comComment Great post!  
I always use Do Until myself.  I NEVER liked:

while not(doc is Nothing)

I think it's because I really don't like working with negatives. Do Until makes a lot more sense to me.

I think I saw some performance testing once that showed that Do Until was at least slightly faster then While Wend.  This was probably in a View Article.. But even if it is slower I'd stick with Do Until for readability.

Just what works for me...  I see While Wend more often then anything so that works great also.
Karl-Henry MartinssonName:Karl-Henry MartinssonWebsite:http://www.bleedyellow.com/blogs/texasswedeComment

I use:

Do While Not doc is Nothing

 

Loop

Let you exit out of it, but still is clearer to me.

Erik BrooksName:Erik BrooksComment

Also check out NotesDocumentCollection.StampAll() and StampAllMulti.

Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.com/blogs/ScriptLarsComment I once had problems with this style of coding:
Do Until collectionPiece Is Nothing
...
...
Set collectionPiece = whateverCollection.GetNext(collectionPiece)
Loop

Ever since then I've used:
Do Until collectionPiece Is Nothing
Set collectionPieceNext = whateverCollection.GetNext(collectionPiece)
...
...
Set collectionPiece = collectionPieceNext
Loop

Advantage: you get the next pice while everything is still fresh, and then you're free to do what you want to the piece.

Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.com/blogs/ScriptLarsComment

I forgot: above code is pseudocode, not real LotusScript, just meant to generalize and show the concept

David LeedyName:David LeedyWebsite:http://notesin9.comComment

Lars - Yeah - will do something like your second code block if I might need to delete the working document... but otherwise I tend to stick to the first code block.

Paul WithersName:Paul WithersWebsite:http://hermes.intec.co.uk/intec/blog.nsfComment I have to admit I tend to use While...Wend, with a Goto Label if I need to get out of the loop. But then that's just out of personal habit. I'm not sure what the performance of that would be compared to Exit Loop in a Do While | Until. Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.com/blogs/ScriptLarsComment

I've developed this style of defensive coding because I get to maintain a  lot of crufty code.  Requirements change, loops must be built, etc... I use this method to avoid unfortunate side-effects and thus also avoid egg on my face caused by cruftiness that was already there.

Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.com/blogs/ScriptLarsComment

@Paul you need an Exit Do to exit the loop...

Timothy BrileyName:Timothy BrileyComment

Ok, I give, why use:

Join(doc.GetItemValue("submitter"), "")

instead of

doc.GetItemValue("submitter")(0)

?

Chris TooheyName:Chris TooheyWebsite:http://www.dominoguru.comComment

Yikes - it's really the simple things that start the best conversations huh?

While Not(doc is Nothing) always felt like Hide-When Formula logic to me.

@Lars:

Yeah, adding the next above the iterative payload is one of those things that you learn to do after you've pulled your hair out trying to figure out why your NotesDocument deletion routine keeps failing. It's an excellent practice, but I was going entry-level iterating with this particular post.

@Timothy:

Dunno, just a habit I've gotten into. I forget why now honestly, but I think it has something to do with Java.

Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.com/blogs/ScriptLarsComment

@Chris that's why I chipped in, hoping to up the level, and save egg... And because we discussed it, they can even read why!

Joseph HoetzlName:Joseph HoetzlWebsite:http://www.josephhoetzl.comComment

Hmmm, just was in a bit of code with this in it:

While Not(Doc Is Nothing)
    Call ExportOne (doc, xlWkshtObj)
    Set Doc = collection.GetNextDocument( doc )
Wend

Do you know if there are any hard/fast rules about performance of a While Not vs a Do Until?

Dan KingName:Dan KingComment

OK, so I've just looked up the View article mentioned above at times for While and Do loops.It was May/June 2006 issue, but I reckon the speeds won't have changed much, at least comparatively.

What it says is there's not a lot of difference. In fact, on a looping test just reading from a doccollection, Do was faster over 100K docs, While over 200K docs, and Do faster again over 300K

So, I think it's just whatever you want to use.

Lars, the defensive coding is only needed if you change the doccollection while looping (eg deleting a doc). I find it's needed more often when looping through a view and changing values that then change the position of docs in views

SelcukName:SelcukComment

Lars, the defensive coding is only needed if you change the doccollection while looping (eg deleting a doc). I find it's needed more often when looping through a view and changing values that then change the position of docs in views

@DanKing:

Dan, you can use view.AutoUpdate = False that prevents position changes of documents while iterating through a view once it is initialized.

Mike McPName:Mike McPWebsite:http://www.openntf.org/Projects/pmt.nsf/ProjectHome?ReadForm&Query=mPortalComment

When I think I'll be doing a large number of 'getdocumentbykeys' in a loop, I prefer to do it this way by first rolling through a view and putting everyone in a list. I believe list lookups are quicker than repeated getdocumentbykey calls.

There's some other tricks to speed it up further

Dim empList List As String Set view = nab.getview("People") view.autoupdate = False Set doc = view.getfirstdocument While Not doc Is Nothing empList( doc.Fullname(0) ) = doc.Manager(0) Set doc = doc.getnextdocument( doc ) Wend 'now, instead of doing getdocumentbykey on a view, we simply check the list Set doc = col.GetFirstDocument While Not(doc Is Nothing) doSave = False If Iselement( empList( doc.submitter(0) )) Then If doc.Manager(0) <> empList( doc.submitter(0)) Then Call doc.ReplaceItemValue("manager", empList( doc.submitter(0))) doSave = True End If End If If doSave = True Then Call doc.Save(True, False, True) End If Set doc = col.GetNextDocument(doc) Wend
tom oneilName:tom oneilComment @Mike McP:

I agree to a point. It's better to cache the manager doc after the first lookup than cache them all at the start of the code. I work in a company of 50,000+ people... imagine what that list would be like. :-)

Dim s As New NotesSession Dim doc As NotesDocument Dim nab As New NotesDatabase(s.CurrentDatabase.Server, "names.nsf") Dim nabview As NotesView Dim nabcol As NotesDocumentCollection Dim nabdoc As NotesDocument Dim empList List As String Set nabview = nab.GetView("people") Set doc = col.GetFirstDocument Do While Not (doc Is Nothing) If Not Iselement(empList(doc.GetItemValue("submitter")(0))) Then Set nabcol = nabview.GetAllDocumentsByKey(Join(doc.GetItemValue("submitter"), ""),True) Set nabdoc = nabcol.GetFirstDocument empList(doc.GetItemValue("submitter")(0)) = nabdoc.GetItemValue("manager")(0) End If Call doc.ReplaceItemValue("manager", empList(doc.GetItemValue("submitter")(0))) Call doc.Save(True, False, True) Set doc = col.GetNextDocument(doc) Loop
Darren DukeName:Darren DukeWebsite:http://blog.darrenduke.netComment Inverse boolean logic snippets are evil. Please for the love of god, everyone start using straight boolean when possible. Like Chris mentions, it is like hide-when formulas and these are the bane of humanity.

While(doc is Not Nothing) is far harder for humans (and the peeps coming in behind you after you are long gone) than Do Until doc is Nothing.

Every time you use inverse boolean logic a puppy dies. Do you want that on your conscience? I don't think so....

Code of maintainability, understandability and readability. If you do, Santa will bring you a Wii.
Mike McPName:Mike McPWebsite:http://www.openntf.org/Projects/pmt.nsf/ProjectHome?ReadForm&Query=mPortalComment

@tom.  Yeah, but I think you might be surprised...give it a shot next time.  Notes list items are quite flexible.

I've used this method with > 40,000 entries in the initial list.  It's still quite quick compared to doing 40k getdocumentbykey calls:)

tom oneilName:tom oneilComment

@Darren

Considering most of us recommended Do While Not (doc Is Nothing)... I think it's readable enough.

In fact... I might use it more considering it irritates the philosophical developer. :-)

Chris TooheyName:Chris TooheyWebsite:http://www.dominoguru.comComment

Lists are amazing, and are really underused in LotusScript. Perhaps that'll be the topic of my next beginner tip!

Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.com/blogs/ScriptLarsComment

Agree lists are amazing.  I usually builds a class managing a list of objects (wrap the list in a class for easy management and passing around).


You MUST remember to build your own objects.  There are several warnings findable in the IBM technotes of keeping large numbers of product objects (a.k.a. the Notes... class objects) in memory.  Notes will keep thousands or millions of custom objects in a list and perform very well. But keep a couple of thousand NotesDocument handy and things slow to a crawl or crash.  That's just because the objects do a lot for us.  Remember we are priviliged to be building on the shoulders of giants in Domino-land.

Ethann CastellName:Ethann CastellWebsite:http://www.caliton.comComment I authored the article in the View and I'd recommend reading it to everyone ;-)

Yes, GetNthDocument is evil! You might increase performance by using a For loop since you already know the number of documents in the view, but still using getNextDocument.
Lars Berntrop-BosName:Lars Berntrop-BosWebsite:http://www.bleedyellow.comComment

While I'd love to read that article, it's currently out of reach for me.  I have to rely on publicly available sources for budgetary reasons.

Dan SicklesName:Dan SicklesComment

Lotusscript lists are amazing and what's also amazing is that in every other programming language they are called Maps or Dictionaries (and even associative arrays).

Most programming languages have lists AND  maps/dictionaries. I would really liked to have had a real list type in Lotusscript all these years (I started  writing LS with R4 alpha) in addition to the map. Sometimes you just need a list of things. No key. No index. Just a list, like a python list or a Java Array List. A Set or Tuple would have been useful too. In a scripting language, these data structures should all be first class types, like the Lotusscript map, I mean list.

But a generic (in the value) map called a list? Hey, that's worked out pretty well. Was this about lists ;-?

Shane CurcuruName:Shane CurcuruWebsite:http://shane.curcuru.name/blog/Comment Lists are the best things since they upgraded some of the @function behavior in R3.  I'm quite happy to use them as just a List of blank strings, when all I need is a Set.

Love the variation of how people do their loops; it would be an interesting survey to see the combinations of Do/While/Until/Not/Nothing.  I definitely agree on thinking about future maintenance, and always using Exit Loop rather than Goto.

And yes, any calls to getNthDocument - unless they're truly only interested in that one Nth document - are evil.

Love the Captcha!
Frank DroegeName:Frank DroegeWebsite:http://www.villa-straylight.comComment

I was always wondering what lists were for - the description in Designer help is somewhat clumsy. Then I found out that they're basically hash tables - and I use these a lot in Java coding. Doh. How did I ever code LS without lists? ;-)


(not published)




Evaluate this Formula: @LowerCase(@Text("FOO"))